couchbase 3.4.1 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +2 -0
  4. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
  5. data/ext/couchbase/core/cluster_options.hxx +0 -1
  6. data/ext/couchbase/core/config_profile.cxx +23 -1
  7. data/ext/couchbase/core/config_profile.hxx +2 -12
  8. data/ext/couchbase/core/impl/analytics.cxx +236 -0
  9. data/ext/couchbase/core/impl/cluster.cxx +0 -1
  10. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
  11. data/ext/couchbase/core/impl/query.cxx +5 -5
  12. data/ext/couchbase/core/io/dns_client.cxx +225 -0
  13. data/ext/couchbase/core/io/dns_client.hxx +19 -188
  14. data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
  15. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +3 -0
  16. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +1 -1
  17. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +12 -12
  18. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
  19. data/ext/couchbase/core/transactions/transaction_context.cxx +1 -0
  20. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
  21. data/ext/couchbase/core/utils/connection_string.cxx +10 -3
  22. data/ext/couchbase/core/utils/connection_string.hxx +3 -3
  23. data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
  24. data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
  25. data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
  26. data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
  27. data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
  28. data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
  29. data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
  30. data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
  31. data/ext/couchbase/couchbase/cluster.hxx +33 -0
  32. data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
  33. data/ext/couchbase/couchbase/query_options.hxx +0 -1
  34. data/ext/couchbase/couchbase/scope.hxx +33 -0
  35. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
  36. data/ext/couchbase/test/CMakeLists.txt +1 -2
  37. data/ext/couchbase/test/test_helper.hxx +1 -1
  38. data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
  39. data/ext/couchbase/test/test_integration_crud.cxx +8 -1
  40. data/ext/couchbase/test/test_integration_examples.cxx +41 -0
  41. data/ext/couchbase/test/test_integration_management.cxx +15 -3
  42. data/ext/couchbase/test/test_integration_search.cxx +601 -0
  43. data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
  44. data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
  45. data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
  46. data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
  47. data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
  48. data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
  49. data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
  50. data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
  51. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
  52. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
  53. data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
  54. data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
  55. data/ext/couchbase/third_party/snappy/snappy.h +19 -4
  56. data/ext/couchbase.cxx +27 -6
  57. data/ext/revisions.rb +3 -3
  58. data/lib/couchbase/cluster.rb +13 -9
  59. data/lib/couchbase/cluster_registry.rb +7 -2
  60. data/lib/couchbase/configuration.rb +3 -4
  61. data/lib/couchbase/options.rb +85 -2
  62. data/lib/couchbase/search_options.rb +158 -240
  63. data/lib/couchbase/version.rb +1 -1
  64. metadata +17 -6
  65. data/ext/couchbase/core/CMakeLists.txt +0 -0
@@ -39,7 +39,9 @@
39
39
  #ifndef THIRD_PARTY_SNAPPY_SNAPPY_H__
40
40
  #define THIRD_PARTY_SNAPPY_SNAPPY_H__
41
41
 
42
- #include <cstddef>
42
+ #include <stddef.h>
43
+ #include <stdint.h>
44
+
43
45
  #include <string>
44
46
 
45
47
  #include "snappy-stubs-public.h"
@@ -63,20 +65,27 @@ namespace snappy {
63
65
  // Also note that this leaves "*source" in a state that is unsuitable for
64
66
  // further operations, such as RawUncompress(). You will need to rewind
65
67
  // or recreate the source yourself before attempting any further calls.
66
- bool GetUncompressedLength(Source* source, uint32* result);
68
+ bool GetUncompressedLength(Source* source, uint32_t* result);
67
69
 
68
70
  // ------------------------------------------------------------------------
69
71
  // Higher-level string based routines (should be sufficient for most users)
70
72
  // ------------------------------------------------------------------------
71
73
 
72
- // Sets "*compressed" to the compressed version of "input[0,input_length-1]".
74
+ // Sets "*compressed" to the compressed version of "input[0..input_length-1]".
73
75
  // Original contents of *compressed are lost.
74
76
  //
75
77
  // REQUIRES: "input[]" is not an alias of "*compressed".
76
78
  size_t Compress(const char* input, size_t input_length,
77
79
  std::string* compressed);
78
80
 
79
- // Decompresses "compressed[0,compressed_length-1]" to "*uncompressed".
81
+ // Same as `Compress` above but taking an `iovec` array as input. Note that
82
+ // this function preprocesses the inputs to compute the sum of
83
+ // `iov[0..iov_cnt-1].iov_len` before reading. To avoid this, use
84
+ // `RawCompressFromIOVec` below.
85
+ size_t CompressFromIOVec(const struct iovec* iov, size_t iov_cnt,
86
+ std::string* compressed);
87
+
88
+ // Decompresses "compressed[0..compressed_length-1]" to "*uncompressed".
80
89
  // Original contents of "*uncompressed" are lost.
81
90
  //
82
91
  // REQUIRES: "compressed[]" is not an alias of "*uncompressed".
@@ -122,6 +131,12 @@ namespace snappy {
122
131
  char* compressed,
123
132
  size_t* compressed_length);
124
133
 
134
+ // Same as `RawCompress` above but taking an `iovec` array as input. Note that
135
+ // `uncompressed_length` is the total number of bytes to be read from the
136
+ // elements of `iov` (_not_ the number of elements in `iov`).
137
+ void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length,
138
+ char* compressed, size_t* compressed_length);
139
+
125
140
  // Given data in "compressed[0..compressed_length-1]" generated by
126
141
  // calling the Snappy::Compress routine, this routine
127
142
  // stores the uncompressed data to
data/ext/couchbase.cxx CHANGED
@@ -1820,8 +1820,9 @@ cb_extract_option_bool(bool& field, VALUE options, const char* name)
1820
1820
  }
1821
1821
  }
1822
1822
 
1823
+ template<typename Integer>
1823
1824
  static void
1824
- cb_extract_option_number(std::size_t& field, VALUE options, const char* name)
1825
+ cb_extract_option_number(Integer& field, VALUE options, const char* name)
1825
1826
  {
1826
1827
  if (!NIL_P(options) && TYPE(options) == T_HASH) {
1827
1828
  VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
@@ -1830,10 +1831,10 @@ cb_extract_option_number(std::size_t& field, VALUE options, const char* name)
1830
1831
  }
1831
1832
  switch (TYPE(val)) {
1832
1833
  case T_FIXNUM:
1833
- field = FIX2ULONG(val);
1834
+ field = static_cast<Integer>(FIX2ULONG(val));
1834
1835
  break;
1835
1836
  case T_BIGNUM:
1836
- field = NUM2ULL(val);
1837
+ field = static_cast<Integer>(NUM2ULL(val));
1837
1838
  break;
1838
1839
  default:
1839
1840
  throw ruby_exception(rb_eArgError, rb_sprintf("%s must be a Integer, but given %+" PRIsVALUE, name, val));
@@ -1884,6 +1885,25 @@ cb_extract_option_string(std::string& target, VALUE options, const char* name);
1884
1885
  static void
1885
1886
  cb_extract_option_symbol(VALUE& val, VALUE options, const char* name);
1886
1887
 
1888
+ static void
1889
+ cb_extract_dns_config(couchbase::core::io::dns::dns_config& config, VALUE options)
1890
+ {
1891
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1892
+ return;
1893
+ }
1894
+
1895
+ auto timeout{ couchbase::core::timeout_defaults::dns_srv_timeout };
1896
+ cb_extract_option_milliseconds(timeout, options, "dns_srv_timeout");
1897
+
1898
+ std::string nameserver{ couchbase::core::io::dns::dns_config::default_nameserver };
1899
+ cb_extract_option_string(nameserver, options, "dns_srv_nameserver");
1900
+
1901
+ std::uint16_t port{ couchbase::core::io::dns::dns_config::default_port };
1902
+ cb_extract_option_number(port, options, "dns_srv_port");
1903
+
1904
+ config = couchbase::core::io::dns::dns_config(nameserver, port, timeout);
1905
+ }
1906
+
1887
1907
  static VALUE
1888
1908
  cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE options)
1889
1909
  {
@@ -1983,13 +2003,14 @@ cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE op
1983
2003
  cb_extract_option_milliseconds(origin.options().analytics_timeout, options, "analytics_timeout");
1984
2004
  cb_extract_option_milliseconds(origin.options().search_timeout, options, "search_timeout");
1985
2005
  cb_extract_option_milliseconds(origin.options().management_timeout, options, "management_timeout");
1986
- cb_extract_option_milliseconds(origin.options().dns_srv_timeout, options, "dns_srv_timeout");
1987
2006
  cb_extract_option_milliseconds(origin.options().tcp_keep_alive_interval, options, "tcp_keep_alive_interval");
1988
2007
  cb_extract_option_milliseconds(origin.options().config_poll_interval, options, "config_poll_interval");
1989
2008
  cb_extract_option_milliseconds(origin.options().config_poll_floor, options, "config_poll_floor");
1990
2009
  cb_extract_option_milliseconds(origin.options().config_idle_redial_timeout, options, "config_idle_redial_timeout");
1991
2010
  cb_extract_option_milliseconds(origin.options().idle_http_connection_timeout, options, "idle_http_connection_timeout");
1992
2011
 
2012
+ cb_extract_dns_config(origin.options().dns_config, options);
2013
+
1993
2014
  cb_extract_option_number(origin.options().max_http_connections, options, "max_http_connections");
1994
2015
 
1995
2016
  cb_extract_option_bool(origin.options().enable_tls, options, "enable_tls");
@@ -6819,12 +6840,12 @@ cb_Backend_dns_srv(VALUE self, VALUE hostname, VALUE service)
6819
6840
  if (tls) {
6820
6841
  service_name = "_couchbases";
6821
6842
  }
6822
- auto barrier = std::make_shared<std::promise<couchbase::core::io::dns::dns_client::dns_srv_response>>();
6843
+ auto barrier = std::make_shared<std::promise<couchbase::core::io::dns::dns_srv_response>>();
6823
6844
  auto f = barrier->get_future();
6824
6845
  client.query_srv(host_name,
6825
6846
  service_name,
6826
6847
  couchbase::core::io::dns::dns_config::system_config(),
6827
- [barrier](couchbase::core::io::dns::dns_client::dns_srv_response&& resp) { barrier->set_value(std::move(resp)); });
6848
+ [barrier](couchbase::core::io::dns::dns_srv_response&& resp) { barrier->set_value(std::move(resp)); });
6828
6849
  ctx.run();
6829
6850
  auto resp = cb_wait_for_future(f);
6830
6851
  if (resp.ec) {
data/ext/revisions.rb CHANGED
@@ -1,3 +1,3 @@
1
- cmake_flags << "-DEXT_GIT_REVISION=97ca42af94afb27b75d35a1f5ea5414a562036a5"
2
- cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_REVISION=b895551ebe99164be6e633e21147296cd7241c34"
3
- cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_DESCRIBE=1.0.0-dp.4-10-gb895551"
1
+ cmake_flags << "-DEXT_GIT_REVISION=527358f7c022f5fa6c93cb4d0f95118db597cc08"
2
+ cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_REVISION=98af5a9a2169c9bba284d3cb1e839b6f5e54c3b8"
3
+ cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_DESCRIBE=1.0.0-dp.4-22-g98af5a9"
@@ -32,13 +32,13 @@ module Couchbase
32
32
 
33
33
  # Connect to the Couchbase cluster
34
34
  #
35
- # @overload connect(connection_string, options)
36
- # @param [String] connection_string connection string used to locate the Couchbase Cluster
35
+ # @overload connect(connection_string_or_config, options)
36
+ # @param [String, Configuration] connection_string_or_config connection string used to locate the Couchbase Cluster
37
37
  # @param [Options::Cluster] options custom options when creating the cluster connection
38
38
  #
39
- # @overload connect(connection_string, username, password, options)
39
+ # @overload connect(connection_string_or_config, username, password, options)
40
40
  # Shortcut for {PasswordAuthenticator}
41
- # @param [String] connection_string connection string used to locate the Couchbase Cluster
41
+ # @param [String] connection_string_or_config connection string used to locate the Couchbase Cluster
42
42
  # @param [String] username name of the user
43
43
  # @param [String] password password of the user
44
44
  # @param [Options::Cluster, nil] options custom options when creating the cluster connection
@@ -62,12 +62,16 @@ module Couchbase
62
62
  # @see https://docs.couchbase.com/server/current/manage/manage-security/configure-client-certificates.html
63
63
  #
64
64
  # @return [Cluster]
65
- def self.connect(connection_string, *options)
66
- regexp = /^((couchbases?|http):\/\/.*)$/i
67
- if regexp.match?(connection_string) || !connection_string.include?("://")
68
- Cluster.new(connection_string, *options)
65
+ def self.connect(connection_string_or_config, *options)
66
+ connection_string = if connection_string_or_config.is_a?(Configuration)
67
+ connection_string_or_config.connection_string
68
+ else
69
+ connection_string_or_config
70
+ end
71
+ if connection_string =~ /\Acouchbases?:\/\/.*\z/i || !connection_string.include?("://")
72
+ Cluster.new(connection_string_or_config, *options)
69
73
  else
70
- ClusterRegistry.instance.connect(connection_string, *options)
74
+ ClusterRegistry.instance.connect(connection_string_or_config, *options)
71
75
  end
72
76
  end
73
77
 
@@ -26,9 +26,14 @@ module Couchbase
26
26
  @handlers = {}
27
27
  end
28
28
 
29
- def connect(connection_string, *options)
29
+ def connect(connection_string_or_config, *options)
30
+ connection_string = if connection_string_or_config.is_a?(Configuration)
31
+ connection_string_or_config.connection_string
32
+ else
33
+ connection_string_or_config
34
+ end
30
35
  @handlers.each do |regexp, cluster_class|
31
- return cluster_class.connect(connection_string, *options) if regexp.match?(connection_string)
36
+ return cluster_class.connect(connection_string_or_config, *options) if regexp.match?(connection_string)
32
37
  end
33
38
  raise(Error::FeatureNotAvailable, "Connection string '#{connection_string}' not supported.")
34
39
  end
@@ -33,10 +33,9 @@ module Couchbase
33
33
  private
34
34
 
35
35
  def load_configuration(settings)
36
- configuration = settings.with_indifferent_access
37
- @connection_string = configuration[:connection_string]
38
- @username = configuration[:username]
39
- @password = configuration[:password]
36
+ @connection_string = settings[:connection_string] || settings["connection_string"]
37
+ @username = settings[:username] || settings["username"]
38
+ @password = settings[:password] || settings["password"]
40
39
  end
41
40
 
42
41
  def load_yaml(path, environment)
@@ -1029,10 +1029,38 @@ module Couchbase
1029
1029
  # Options for {BinaryCollection#append}
1030
1030
  class Append < Base
1031
1031
  attr_accessor :cas # @return [Integer]
1032
+ attr_accessor :durability_level # @return [Symbol]
1033
+ attr_accessor :replicate_to # @return [Symbol]
1034
+ attr_accessor :persist_to # @return [Symbol]
1032
1035
 
1033
1036
  # Creates an instance of options for {BinaryCollection#append}
1034
1037
  #
1035
1038
  # @param [Integer] cas The default CAS used (0 means no CAS in this context)
1039
+ # @param [Symbol] durability_level level of durability
1040
+ # +:none+::
1041
+ # no enhanced durability required for the mutation
1042
+ # +:majority+::
1043
+ # the mutation must be replicated to a majority of the Data Service nodes
1044
+ # (that is, held in the memory allocated to the bucket)
1045
+ # +:majority_and_persist_to_active+::
1046
+ # The mutation must be replicated to a majority of the Data Service nodes.
1047
+ # Additionally, it must be persisted (that is, written and synchronised to disk) on the
1048
+ # node hosting the active partition (vBucket) for the data.
1049
+ # +:persist_to_majority+::
1050
+ # The mutation must be persisted to a majority of the Data Service nodes.
1051
+ # Accordingly, it will be written to disk on those nodes.
1052
+ # @param [Symbol] replicate_to number of nodes to replicate
1053
+ # +:none+:: do not apply any replication requirements.
1054
+ # +:one+:: wait for replication to at least one node.
1055
+ # +:two+:: wait for replication to at least two nodes.
1056
+ # +:three+:: wait for replication to at least three nodes.
1057
+ # @param [Symbol] persist_to number of nodes to persist
1058
+ # +:none+:: do not apply any persistence requirements.
1059
+ # +:active+:: wait for persistence to active node
1060
+ # +:one+:: wait for persistence to at least one node.
1061
+ # +:two+:: wait for persistence to at least two nodes.
1062
+ # +:three+:: wait for persistence to at least three nodes.
1063
+ # +:four+:: wait for persistence to four nodes (active and replicas).
1036
1064
  #
1037
1065
  # @param [Integer, #in_milliseconds, nil] timeout
1038
1066
  # @param [Proc, nil] retry_strategy the custom retry strategy, if set
@@ -1041,12 +1069,23 @@ module Couchbase
1041
1069
  #
1042
1070
  # @yieldparam [Append] self
1043
1071
  def initialize(cas: nil,
1072
+ durability_level: :none,
1073
+ replicate_to: :none,
1074
+ persist_to: :none,
1044
1075
  timeout: nil,
1045
1076
  retry_strategy: nil,
1046
1077
  client_context: nil,
1047
1078
  parent_span: nil)
1048
1079
  super(timeout: timeout, retry_strategy: retry_strategy, client_context: client_context, parent_span: parent_span)
1049
1080
  @cas = cas
1081
+
1082
+ if durability_level != :none && (replicate_to != :none || persist_to != :none)
1083
+ raise ArgumentError, "durability_level conflicts with replicate_to and persist_to options"
1084
+ end
1085
+
1086
+ @durability_level = durability_level
1087
+ @replicate_to = replicate_to
1088
+ @persist_to = persist_to
1050
1089
  yield self if block_given?
1051
1090
  end
1052
1091
 
@@ -1055,6 +1094,9 @@ module Couchbase
1055
1094
  {
1056
1095
  timeout: Utils::Time.extract_duration(@timeout),
1057
1096
  cas: @cas,
1097
+ durability_level: @durability_level,
1098
+ persist_to: @persist_to,
1099
+ replicate_to: @replicate_to,
1058
1100
  }
1059
1101
  end
1060
1102
 
@@ -1064,12 +1106,39 @@ module Couchbase
1064
1106
 
1065
1107
  # Options for {BinaryCollection#prepend}
1066
1108
  class Prepend < Base
1067
- # @return [Integer] The default CAS used (0 means no CAS in this context)
1068
- attr_accessor :cas
1109
+ attr_accessor :cas # @return [Integer]
1110
+ attr_accessor :durability_level # @return [Symbol]
1111
+ attr_accessor :replicate_to # @return [Symbol]
1112
+ attr_accessor :persist_to # @return [Symbol]
1069
1113
 
1070
1114
  # Creates an instance of options for {BinaryCollection#prepend}
1071
1115
  #
1072
1116
  # @param [Integer] cas The default CAS used (0 means no CAS in this context)
1117
+ # @param [Symbol] durability_level level of durability
1118
+ # +:none+::
1119
+ # no enhanced durability required for the mutation
1120
+ # +:majority+::
1121
+ # the mutation must be replicated to a majority of the Data Service nodes
1122
+ # (that is, held in the memory allocated to the bucket)
1123
+ # +:majority_and_persist_to_active+::
1124
+ # The mutation must be replicated to a majority of the Data Service nodes.
1125
+ # Additionally, it must be persisted (that is, written and synchronised to disk) on the
1126
+ # node hosting the active partition (vBucket) for the data.
1127
+ # +:persist_to_majority+::
1128
+ # The mutation must be persisted to a majority of the Data Service nodes.
1129
+ # Accordingly, it will be written to disk on those nodes.
1130
+ # @param [Symbol] replicate_to number of nodes to replicate
1131
+ # +:none+:: do not apply any replication requirements.
1132
+ # +:one+:: wait for replication to at least one node.
1133
+ # +:two+:: wait for replication to at least two nodes.
1134
+ # +:three+:: wait for replication to at least three nodes.
1135
+ # @param [Symbol] persist_to number of nodes to persist
1136
+ # +:none+:: do not apply any persistence requirements.
1137
+ # +:active+:: wait for persistence to active node
1138
+ # +:one+:: wait for persistence to at least one node.
1139
+ # +:two+:: wait for persistence to at least two nodes.
1140
+ # +:three+:: wait for persistence to at least three nodes.
1141
+ # +:four+:: wait for persistence to four nodes (active and replicas).
1073
1142
  #
1074
1143
  # @param [Integer, #in_milliseconds, nil] timeout
1075
1144
  # @param [Proc, nil] retry_strategy the custom retry strategy, if set
@@ -1078,12 +1147,23 @@ module Couchbase
1078
1147
  #
1079
1148
  # @yieldparam [Prepend] self
1080
1149
  def initialize(cas: nil,
1150
+ durability_level: :none,
1151
+ replicate_to: :none,
1152
+ persist_to: :none,
1081
1153
  timeout: nil,
1082
1154
  retry_strategy: nil,
1083
1155
  client_context: nil,
1084
1156
  parent_span: nil)
1085
1157
  super(timeout: timeout, retry_strategy: retry_strategy, client_context: client_context, parent_span: parent_span)
1086
1158
  @cas = cas
1159
+
1160
+ if durability_level != :none && (replicate_to != :none || persist_to != :none)
1161
+ raise ArgumentError, "durability_level conflicts with replicate_to and persist_to options"
1162
+ end
1163
+
1164
+ @durability_level = durability_level
1165
+ @replicate_to = replicate_to
1166
+ @persist_to = persist_to
1087
1167
  yield self if block_given?
1088
1168
  end
1089
1169
 
@@ -1092,6 +1172,9 @@ module Couchbase
1092
1172
  {
1093
1173
  timeout: Utils::Time.extract_duration(@timeout),
1094
1174
  cas: @cas,
1175
+ durability_level: @durability_level,
1176
+ persist_to: @persist_to,
1177
+ replicate_to: @replicate_to,
1095
1178
  }
1096
1179
  end
1097
1180