aerospike 2.6.0 → 2.7.0

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +3 -1
  4. data/lib/aerospike.rb +9 -5
  5. data/lib/aerospike/client.rb +101 -83
  6. data/lib/aerospike/cluster.rb +11 -50
  7. data/lib/aerospike/cluster/create_connection.rb +1 -1
  8. data/lib/aerospike/cluster/find_nodes_to_remove.rb +66 -0
  9. data/lib/aerospike/cluster/partition.rb +5 -2
  10. data/lib/aerospike/command/batch_direct_command.rb +104 -0
  11. data/lib/aerospike/command/batch_direct_exists_command.rb +51 -0
  12. data/lib/aerospike/command/batch_direct_node.rb +40 -0
  13. data/lib/aerospike/command/batch_index_command.rb +119 -0
  14. data/lib/aerospike/command/batch_index_exists_command.rb +45 -0
  15. data/lib/aerospike/command/batch_index_node.rb +52 -0
  16. data/lib/aerospike/command/batch_item.rb +18 -47
  17. data/lib/aerospike/command/command.rb +6 -65
  18. data/lib/aerospike/command/field_type.rb +13 -10
  19. data/lib/aerospike/command/{batch_command.rb → multi_command.rb} +29 -9
  20. data/lib/aerospike/command/read_command.rb +4 -2
  21. data/lib/aerospike/command/single_command.rb +6 -9
  22. data/lib/aerospike/connection/create.rb +3 -3
  23. data/lib/aerospike/host/parse.rb +28 -2
  24. data/lib/aerospike/node.rb +6 -2
  25. data/lib/aerospike/node/refresh/friends.rb +1 -1
  26. data/lib/aerospike/node/refresh/peers.rb +1 -1
  27. data/lib/aerospike/node_validator.rb +3 -3
  28. data/lib/aerospike/peers.rb +4 -0
  29. data/lib/aerospike/peers/parse.rb +26 -6
  30. data/lib/aerospike/policy/batch_policy.rb +25 -15
  31. data/lib/aerospike/policy/client_policy.rb +2 -2
  32. data/lib/aerospike/policy/query_policy.rb +25 -12
  33. data/lib/aerospike/policy/scan_policy.rb +39 -16
  34. data/lib/aerospike/query/stream_command.rb +6 -5
  35. data/lib/aerospike/record.rb +4 -3
  36. data/lib/aerospike/socket/ssl.rb +13 -13
  37. data/lib/aerospike/socket/tcp.rb +8 -1
  38. data/lib/aerospike/utils/string_parser.rb +7 -3
  39. data/lib/aerospike/version.rb +1 -1
  40. metadata +11 -7
  41. data/lib/aerospike/command/batch_command_exists.rb +0 -93
  42. data/lib/aerospike/command/batch_command_get.rb +0 -84
  43. data/lib/aerospike/command/batch_node.rb +0 -82
@@ -21,10 +21,10 @@ module Aerospike
21
21
  module Connection # :nodoc:
22
22
  module Create
23
23
  class << self
24
- def call(host, port, timeout: 30, tls_name: nil, ssl_options: nil)
25
- if !ssl_options.nil? && ssl_options[:enable] != false
24
+ def call(host, port, timeout: 30, tls_name: nil, tls_options: nil)
25
+ if !tls_options.nil? && tls_options[:enable] != false
26
26
  ::Aerospike::Socket::SSL.connect(
27
- host, port, timeout, tls_name, ssl_options
27
+ host, port, timeout, tls_name, tls_options
28
28
  )
29
29
  else
30
30
  ::Aerospike::Socket::TCP.connect(host, port, timeout)
@@ -23,7 +23,14 @@ module Aerospike
23
23
  INTEGER_REGEX = /\A\d+\z/
24
24
 
25
25
  class << self
26
- # Parse hosts from string format: hostname1[:tlsname1][:port1],...
26
+ ##
27
+ # Parse hosts from string format: hostname1[:tlsname1][:port1],...
28
+ #
29
+ # Hostname may also be an IP address in the following formats:
30
+ # - xxx.xxx.xxx.xxx
31
+ # - [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
32
+ # - [xxxx::xxxx]
33
+ #
27
34
  def call(hosts, default_port = 3000)
28
35
  case hosts
29
36
  when Host
@@ -32,7 +39,7 @@ module Aerospike
32
39
  hosts
33
40
  when String
34
41
  hosts.split(?,).map { |host|
35
- addr, tls_name, port = host.split(?:)
42
+ addr, tls_name, port = components(host)
36
43
  if port.nil? && tls_name && tls_name.match(INTEGER_REGEX)
37
44
  port = tls_name
38
45
  tls_name = nil
@@ -44,6 +51,25 @@ module Aerospike
44
51
  fail TypeError, "hosts should be a Host object, an Array of Host objects, or a String"
45
52
  end
46
53
  end
54
+
55
+ # Extract addr, tls_name and port components from a host strin
56
+ def components(host_string)
57
+ host_string = host_string.strip
58
+
59
+ # IPv6
60
+ if host_string.start_with?('[')
61
+ end_idx = host_string.index(']')
62
+ raise ::Aerospike::Exceptions::Parse, 'Invalid IPv6 host' if end_idx.nil?
63
+
64
+ # Slice away brackets and what's inside them, then split on : and
65
+ # replace first entry with string inside brackets
66
+ host_string.slice(end_idx+1..-1).split(':').tap do |result|
67
+ result[0] = host_string[1...end_idx]
68
+ end
69
+ else
70
+ host_string.split(?:)
71
+ end
72
+ end
47
73
  end
48
74
  end
49
75
  end
@@ -139,6 +139,10 @@ module Aerospike
139
139
  @reference_count.value = 0
140
140
  end
141
141
 
142
+ def referenced?
143
+ @reference_count.value > 0
144
+ end
145
+
142
146
  def responded!
143
147
  @responded.value = true
144
148
  end
@@ -155,8 +159,8 @@ module Aerospike
155
159
  @peers_count.value > 0
156
160
  end
157
161
 
158
- def failed?
159
- @failures.value > 0
162
+ def failed?(threshold = 1)
163
+ @failures.value >= threshold
160
164
  end
161
165
 
162
166
  def failed!
@@ -60,7 +60,7 @@ module Aerospike
60
60
  host,
61
61
  cluster.connection_timeout,
62
62
  cluster.cluster_name,
63
- cluster.ssl_options
63
+ cluster.tls_options
64
64
  )
65
65
 
66
66
  node = peers.find_node_by_name(nv.name)
@@ -41,7 +41,7 @@ module Aerospike
41
41
 
42
42
  peer.hosts.each do |host|
43
43
  begin
44
- nv = NodeValidator.new(cluster, host, cluster.connection_timeout, cluster.cluster_name, cluster.ssl_options)
44
+ nv = NodeValidator.new(cluster, host, cluster.connection_timeout, cluster.cluster_name, cluster.tls_options)
45
45
 
46
46
  if nv.name != peer.node_name
47
47
  ::Aerospike.logger.warn("Peer node #{peer.node_name} is different than actual node #{nv.name} for host #{host}");
@@ -21,15 +21,15 @@ module Aerospike
21
21
  class NodeValidator # :nodoc:
22
22
  VERSION_REGEXP = /(?<v1>\d+)\.(?<v2>\d+)\.(?<v3>\d+).*/.freeze
23
23
 
24
- attr_reader :host, :aliases, :name, :use_new_info, :features, :cluster_name, :ssl_options, :conn
24
+ attr_reader :host, :aliases, :name, :use_new_info, :features, :cluster_name, :tls_options, :conn
25
25
 
26
- def initialize(cluster, host, timeout, cluster_name, ssl_options = {})
26
+ def initialize(cluster, host, timeout, cluster_name, tls_options = {})
27
27
  @cluster = cluster
28
28
  @use_new_info = true
29
29
  @features = Set.new
30
30
  @host = host
31
31
  @cluster_name = cluster_name
32
- @ssl_options = ssl_options
32
+ @tls_options = tls_options
33
33
 
34
34
  set_aliases(host)
35
35
  set_address(timeout)
@@ -37,6 +37,10 @@ module Aerospike
37
37
  @generation_changed == true
38
38
  end
39
39
 
40
+ def reset_refresh_count!
41
+ @refresh_count = 0
42
+ end
43
+
40
44
  def use_peers?
41
45
  @use_peers == true
42
46
  end
@@ -72,15 +72,35 @@ module Aerospike
72
72
  end
73
73
 
74
74
  def parse_hosts(parser, peer)
75
+ result = []
75
76
  parser.expect('[')
76
- return [] if parser.current == ']'
77
+ return result if parser.current == ']'
77
78
 
78
- # TODO(wallin): handle IPv6
79
- raise ::Aerospike::Exceptions::Parse if parser.current == '['
80
- parser.read_until(']').split(',').map do |host|
81
- hostname, port = host.split(':')
82
- ::Aerospike::Host.new(hostname, port, peer.tls_name)
79
+ loop do
80
+ result << parse_host(parser, peer)
81
+ break if parser.current == ']'
83
82
  end
83
+
84
+ result
85
+ end
86
+
87
+ def parse_host(parser, peer)
88
+ if parser.current == '[' # IPv6
89
+ parser.step
90
+ host = parser.read_until(']')
91
+ # skip one extra if port is detected, to match read behavior below
92
+ parser.step if parser.current == ':'
93
+ else
94
+ host = parser.read_until(',', ':', ']')
95
+ end
96
+
97
+ port = parser.prev == ':' ? parser.read_until(',', ']').to_i : nil
98
+
99
+ if parser.prev == ',' || parser.prev == ']'
100
+ return ::Aerospike::Host.new(host, port, peer.tls_name)
101
+ end
102
+
103
+ raise ::Aerospike::Exceptions::Parse, "Unterminated host in response"
84
104
  end
85
105
  end
86
106
  end
@@ -1,17 +1,19 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
1
+ # Copyright 2014-2018 Aerospike, Inc.
3
2
  #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
3
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
4
+ # license agreements.
7
5
  #
8
- # http:#www.apache.org/licenses/LICENSE-2.0
6
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ # use this file except in compliance with the License. You may obtain a copy of
8
+ # the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
9
11
  #
10
12
  # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations under
16
+ # the License.
15
17
 
16
18
  require 'aerospike/policy/policy'
17
19
 
@@ -20,15 +22,23 @@ module Aerospike
20
22
  # Container object for batch policy command.
21
23
  class BatchPolicy < Policy
22
24
 
23
- attr_accessor :max_concurrent_nodes, :record_queue_size,
24
- :wait_until_migrations_are_over
25
+ attr_accessor :use_batch_direct
25
26
 
26
27
  def initialize(opt={})
27
28
  super(opt)
28
29
 
29
- @max_concurrent_nodes = opt[:max_concurrent_nodes] || 0
30
- @record_queue_size = opt[:record_queue_size] || 5000
31
- @wait_until_migrations_are_over = opt[:wait_until_migrations_are_over].nil? ? false : wait_until_migrations_are_over
30
+ # Use old batch direct protocol where batch reads are handled by direct
31
+ # low-level batch server database routines. The batch direct protocol can
32
+ # be faster when there is a single namespace. But there is one important
33
+ # drawback: The batch direct protocol will not proxy to a different
34
+ # server node when the mapped node has migrated a record to another node
35
+ # (resulting in not found record). This can happen after a node has been
36
+ # added/removed from the cluster and there is a lag between records being
37
+ # migrated and client partition map update (once per second). The batch
38
+ # index protocol will perform this record proxy when necessary.
39
+ #
40
+ # Default: false (use new batch index protocol if server supports it)
41
+ @use_batch_direct = opt.fetch(:use_batch_direct) { false }
32
42
 
33
43
  self
34
44
  end
@@ -25,7 +25,7 @@ module Aerospike
25
25
  attr_accessor :user, :password
26
26
  attr_accessor :timeout, :connection_queue_size, :fail_if_not_connected, :tend_interval
27
27
  attr_accessor :cluster_name
28
- attr_accessor :ssl_options
28
+ attr_accessor :tls
29
29
 
30
30
  def initialize(opt={})
31
31
  # Initial host connection timeout in seconds. The timeout when opening a connection
@@ -51,7 +51,7 @@ module Aerospike
51
51
  # Cluster Name
52
52
  @cluster_name = opt[:cluster_name]
53
53
 
54
- @ssl_options = opt[:ssl_options]
54
+ @tls = opt[:tls] || opt[:ssl_options]
55
55
  end
56
56
 
57
57
  def requires_authentication
@@ -1,34 +1,47 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
1
+ # Copyright 2014-2018 Aerospike, Inc.
3
2
  #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
3
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
4
+ # license agreements.
7
5
  #
8
- # http:#www.apache.org/licenses/LICENSE-2.0
6
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ # use this file except in compliance with the License. You may obtain a copy of
8
+ # the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
9
11
  #
10
12
  # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations under
16
+ # the License.
15
17
 
16
- require 'aerospike/policy/batch_policy'
18
+ require 'aerospike/policy/policy'
17
19
 
18
20
  module Aerospike
19
21
 
20
22
  # Container object for query policy command.
21
- class QueryPolicy < BatchPolicy
23
+ class QueryPolicy < Policy
22
24
 
23
25
  attr_accessor :include_bin_data
26
+ attr_accessor :record_queue_size
24
27
 
25
28
  def initialize(opt={})
26
29
  super(opt)
27
30
 
28
31
  @max_retries = 0
29
32
 
33
+ # Indicates if bin data is retrieved. If false, only record digests (and
34
+ # user keys if stored on the server) are retrieved.
35
+ # Default is true.
30
36
  @include_bin_data = opt.fetch(:include_bin_data, true)
31
37
 
38
+ # Number of records to place in queue before blocking. Records received
39
+ # from multiple server nodes will be placed in a queue. A separate thread
40
+ # consumes these records in parallel. If the queue is full, the producer
41
+ # threads will block until records are consumed.
42
+ # Default is 5000.
43
+ @record_queue_size = opt[:record_queue_size] || 5000
44
+
32
45
  self
33
46
  end
34
47
 
@@ -1,40 +1,63 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
1
+ # Copyright 2014-2018 Aerospike, Inc.
3
2
  #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
3
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
4
+ # license agreements.
7
5
  #
8
- # http:#www.apache.org/licenses/LICENSE-2.0
6
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ # use this file except in compliance with the License. You may obtain a copy of
8
+ # the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
9
11
  #
10
12
  # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations under
16
+ # the License.
15
17
 
16
- require 'aerospike/policy/batch_policy'
18
+ require 'aerospike/policy/policy'
17
19
 
18
20
  module Aerospike
19
21
 
20
22
  # Container object for scan policy command.
21
- class ScanPolicy < BatchPolicy
23
+ class ScanPolicy < Policy
22
24
 
23
25
  attr_accessor :scan_percent
24
26
  attr_accessor :concurrent_nodes
25
27
  attr_accessor :include_bin_data
26
28
  attr_accessor :fail_on_cluster_change
27
29
  attr_accessor :socket_timeout
30
+ attr_accessor :record_queue_size
28
31
 
29
32
  def initialize(opt={})
30
33
  super(opt)
31
34
 
35
+ @max_retries = 0
36
+
37
+ # Percent of data to scan. Valid integer range is 1 to 100.
38
+ # Default is 100.
32
39
  @scan_percent = opt[:scan_percent] || 100
33
- @concurrent_nodes = opt[:concurrent_nodes].nil? ? true : concurrent_nodes
34
- @include_bin_data = opt[:include_bin_data].nil? ? true : include_bin_data
35
- @fail_on_cluster_change = opt[:fail_on_cluster_change].nil? ? true : fail_on_cluster_change
40
+
41
+ # Issue scan requests in parallel or serially.
42
+ @concurrent_nodes = opt.fetch(:concurrent_nodes) { true }
43
+
44
+ # Indicates if bin data is retrieved. If false, only record digests (and
45
+ # user keys if stored on the server) are retrieved.
46
+ # Default is true.
47
+ @include_bin_data = opt.fetch(:include_bin_data) { true }
48
+
49
+ # Terminate scan if cluster in fluctuating state.
50
+ # Default is true.
51
+ @fail_on_cluster_change = opt.fetch(:fail_on_cluster_change) { true }
52
+
36
53
  @socket_timeout = opt[:socket_timeout] || 10000
37
- @max_retries = 0
54
+
55
+ # Number of records to place in queue before blocking. Records received
56
+ # from multiple server nodes will be placed in a queue. A separate thread
57
+ # consumes these records in parallel. If the queue is full, the producer
58
+ # threads will block until records are consumed.
59
+ # Default is 5000.
60
+ @record_queue_size = opt[:record_queue_size] || 5000
38
61
 
39
62
  self
40
63
  end
@@ -1,12 +1,13 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
1
+ # Copyright 2014-2018 Aerospike, Inc.
3
2
  #
4
3
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
4
  # license agreements.
6
5
  #
7
6
  # Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
7
  # use this file except in compliance with the License. You may obtain a copy of
9
- # the License at http:#www.apache.org/licenses/LICENSE-2.0
8
+ # the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
10
11
  #
11
12
  # Unless required by applicable law or agreed to in writing, software
12
13
  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
@@ -24,9 +25,9 @@ module Aerospike
24
25
 
25
26
  private
26
27
 
27
- class StreamCommand < BatchCommand #:nodoc:
28
+ class StreamCommand < MultiCommand #:nodoc:
28
29
 
29
- def parse_record_results(receive_size)
30
+ def parse_group(receive_size)
30
31
  @data_offset = 0
31
32
 
32
33
  while @data_offset < receive_size
@@ -1,12 +1,13 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
1
+ # Copyright 2014-2018 Aerospike, Inc.
3
2
  #
4
3
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
4
  # license agreements.
6
5
  #
7
6
  # Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
7
  # use this file except in compliance with the License. You may obtain a copy of
9
- # the License at http://www.apache.org/licenses/LICENSE-2.0
8
+ # the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
10
11
  #
11
12
  # Unless required by applicable law or agreed to in writing, software
12
13
  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT