aerospike 2.24.0 → 2.26.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edbb7242a54e005f9be1be27da358cca13e6a0ce74013976610eb6c16d99fd45
4
- data.tar.gz: fa8f76a0176381cd41ec11a6554589bfed9b90c2630bb2e4a1551d2704dac26a
3
+ metadata.gz: 569388197af73988d3965e15f8b7caf42605896f21183a0e6f7d507690dec816
4
+ data.tar.gz: dfe35172403817d176aecfd83747e6155a961b92960a97f8efc713a6b7540d23
5
5
  SHA512:
6
- metadata.gz: 4369da31ee5502c9aca145e11777ca39c2a1a4c0d08ff539375a0f4c05aea4d6113a70ee2f645c4c5c3b01b483bf481fa1e2ca5598ff099126827101f1bdadf7
7
- data.tar.gz: fdc7964d17f671795a3fd09d786b809eeeba88cc435ae336072ca7aff1767b8cd0b778bf28fbb27dd4e3651d976ca74b179d8379c8f57a833c4e3dbaa861dd6e
6
+ metadata.gz: e4de68155586c168c75a51c71749531becdf066cb22888745f8473237cb775dd9054c6401e44a04b00bee517848859d128141692da3fc7c970df2f202e5e49b9
7
+ data.tar.gz: 7c041a196f2bf45a3ff575426b9269ba45c10e16f641c82f5ce11e362ace013d2480c407b8f1e9a663a27bcf78df1988d6af46de2bd22d41c0fce5366fb2a52c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.26.0] 2022-12-02
6
+
7
+ - **New Features**
8
+ - [CLIENT-1808] Support creating a secondary index on elements within a CDT using `Context`.
9
+ - [CLIENT-1991] Add base64 encoding methods to `Context`.
10
+ - [CLIENT-2007] Support using `Context` in query filters.
11
+
12
+ ## [2.25.0] 2022-11-28
13
+
14
+ - **New Features**
15
+
16
+ - [CLIENT-1984] Support scan-show and query-show info commands.
17
+
18
+ - [CLIENT-1362] Adds support Aerospike Expression filters. Expression filters are now supported on all commands, including `Client#get`, `Client#put`, `Client#delete`, `Client#operate`, `Client#scan`, `Client#query`, `Client#execute_udf`, etc.
19
+
20
+ - Adds `Policy#filter_exp` and `Policy#fail_on_filtered_out`
21
+
22
+ - Bit expressions: `Exp::Bit::` `#resize`, `#insert`, `#remove`, `#set`, `#or`, `#xor`, `#and`, `#not`, `#lshift`, `#rshift`, `#add`, `#subtract`, `#set_int`, `#get`, `#count`, `#lscan`, `#rscan`, `#get_int`, `#pack_math`, `#pack_get_int`, `#add_write`, `#add_read`
23
+
24
+ - HLL Expressions: `Exp::HLL::` `#init`, `#add`, `#get_count`, `#get_union`, `#get_union_count`, `#get_intersect_count`, `#get_similarity`, `#describe`, `#may_contain`, `#add_write`, `#add_read`
25
+
26
+ - Map Expressions: `Exp::Map::` `#put`, `#put_items`, `#increment`, `#clear`, `#remove_by_key`, `#remove_by_key_list`, `#remove_by_key_range`, `#remove_by_key_relative_index_range`, `#remove_by_value`, `#remove_by_value_list`, `#remove_by_value_range`, `#remove_by_value_relative_rank_range`, `#remove_by_value_relative_rank_range`, `#remove_by_index`, `#remove_by_index_range`, `#remove_by_rank`, `#remove_by_rank_range`, `#size`, `#get_by_key`, `#get_by_key_range`, `#get_by_key_list`, `#get_by_key_relative_index_range`, `#get_by_key_relative_index_range`, `#get_by_value`, `#get_by_value_range`, `#get_by_value_list`, `#get_by_value_relative_rank_range`, `#get_by_index`, `#get_by_index_range`, `#get_by_rank`, `#get_by_rank_range`, `#add_write`, `#add_read`, `#get_value_type`
27
+
28
+ - List Expressions: `Exp::List::` `#append`, `#append_items`, `#insert`, `#insert_items`, `#increment`, `#set`, `#clear`, `#sort`, `#remove_by_value`, `#remove_by_value_list`, `#remove_by_value_range`, `#remove_by_value_relative_rank_range`, `#remove_by_index`, `#remove_by_index_range`, `#remove_by_rank`, `#remove_by_rank_range`, `#size`, `#get_by_value`, `#get_by_value_range`, `#get_by_value_list`, `#get_by_value_relative_rank_range`, `#get_by_index`, `#get_by_index_range`, `#get_by_index_range`, `#get_by_rank`, `#get_by_rank_range`, `#get_by_rank_range`, `#add_write`, `#add_read`, `#get_value_type`, `#pack_range_operation`
29
+
30
+ - Read and Write operations: `Exp::Operation::` `#write`, `#read`
31
+
5
32
  ## [2.24.0] 2022-11-15
6
33
 
7
34
  - **New Features**
@@ -17,16 +17,17 @@
17
17
  # License for the specific language governing permissions and limitations under
18
18
  # the License.
19
19
 
20
+ require "base64"
21
+
20
22
  module Aerospike
21
23
  module CDT
22
24
 
23
- ##
24
- # Nested CDT context. Identifies the location of nested list/map to apply the operation.
25
- # for the current level.
26
- # An array of CTX identifies location of the list/map on multiple
27
- # levels on nesting.
25
+ ##
26
+ # Nested CDT context. Identifies the location of nested list/map to apply the operation.
27
+ # for the current level.
28
+ # An array of CTX identifies location of the list/map on multiple
29
+ # levels on nesting.
28
30
  class Context
29
-
30
31
  attr_accessor :id, :value
31
32
 
32
33
  def initialize(id, value)
@@ -37,64 +38,64 @@ module Aerospike
37
38
  ##
38
39
  # Create list with given type at index offset, given an order and pad.
39
40
  def self.list_index_create(index, order, pad)
40
- Context.new(0x10 | ListOrder.flag(order, pad), index)
41
- end
42
-
43
- ##
44
- # Lookup list by index offset.
45
- # If the index is negative, the resolved index starts backwards from end of list.
46
- # If an index is out of bounds, a parameter error will be returned.
47
- # Examples:
48
- # 0: First item.
49
- # 4: Fifth item.
50
- # -1: Last item.
51
- # -3: Third to last item.
52
- def self.list_index(index)
53
- Context.new(0x10, index)
54
- end
55
-
56
- ##
57
- # Lookup list by rank.
58
- # 0 = smallest value
59
- # N = Nth smallest value
60
- # -1 = largest value
61
- def self.list_rank(rank)
62
- Context.new(0x11, rank)
63
- end
64
-
65
- ##
66
- # Lookup list by value.
67
- def self.list_value(key)
68
- Context.new(0x13, key)
69
- end
70
-
71
- ##
72
- # Lookup map by index offset.
73
- # If the index is negative, the resolved index starts backwards from end of list.
74
- # If an index is out of bounds, a parameter error will be returned.
75
- # Examples:
76
- # 0: First item.
77
- # 4: Fifth item.
78
- # -1: Last item.
79
- # -3: Third to last item.
80
- def self.map_index(index)
81
- Context.new(0x20, index)
82
- end
83
-
84
- ##
85
- # Lookup map by rank.
86
- # 0 = smallest value
87
- # N = Nth smallest value
88
- # -1 = largest value
89
- def self.map_rank(rank)
90
- Context.new(0x21, rank)
91
- end
92
-
93
- ##
94
- # Lookup map by key.
95
- def self.map_key(key)
96
- Context.new(0x22, key)
97
- end
41
+ Context.new(0x10 | ListOrder.flag(order, pad), index)
42
+ end
43
+
44
+ ##
45
+ # Lookup list by index offset.
46
+ # If the index is negative, the resolved index starts backwards from end of list.
47
+ # If an index is out of bounds, a parameter error will be returned.
48
+ # Examples:
49
+ # 0: First item.
50
+ # 4: Fifth item.
51
+ # -1: Last item.
52
+ # -3: Third to last item.
53
+ def self.list_index(index)
54
+ Context.new(0x10, index)
55
+ end
56
+
57
+ ##
58
+ # Lookup list by rank.
59
+ # 0 = smallest value
60
+ # N = Nth smallest value
61
+ # -1 = largest value
62
+ def self.list_rank(rank)
63
+ Context.new(0x11, rank)
64
+ end
65
+
66
+ ##
67
+ # Lookup list by value.
68
+ def self.list_value(key)
69
+ Context.new(0x13, key)
70
+ end
71
+
72
+ ##
73
+ # Lookup map by index offset.
74
+ # If the index is negative, the resolved index starts backwards from end of list.
75
+ # If an index is out of bounds, a parameter error will be returned.
76
+ # Examples:
77
+ # 0: First item.
78
+ # 4: Fifth item.
79
+ # -1: Last item.
80
+ # -3: Third to last item.
81
+ def self.map_index(index)
82
+ Context.new(0x20, index)
83
+ end
84
+
85
+ ##
86
+ # Lookup map by rank.
87
+ # 0 = smallest value
88
+ # N = Nth smallest value
89
+ # -1 = largest value
90
+ def self.map_rank(rank)
91
+ Context.new(0x21, rank)
92
+ end
93
+
94
+ ##
95
+ # Lookup map by key.
96
+ def self.map_key(key)
97
+ Context.new(0x22, key)
98
+ end
98
99
 
99
100
  ##
100
101
  # Create map with given type at map key.
@@ -102,12 +103,78 @@ module Aerospike
102
103
  Context.new(0x22 | order[:flag], key)
103
104
  end
104
105
 
105
- ##
106
- # Lookup map by value.
107
- def self.map_value(key)
108
- Context.new(0x23, key)
109
- end
106
+ ##
107
+ # Lookup map by value.
108
+ def self.map_value(key)
109
+ Context.new(0x23, key)
110
+ end
111
+
112
+ ##
113
+ # Encodes the context via message pack.
114
+ def self.pack(packer, ctx)
115
+ unless ctx.to_a.empty?
116
+ packer.write_array_header(2)
117
+ ctx.each do |c|
118
+ packer.write(c.id)
119
+ Value.of(c.value)
120
+ end
121
+ end
122
+ end
123
+
124
+ ##
125
+ # Encodes the context via message pack and return the results.
126
+ def self.bytes(ctx)
127
+ unless ctx.to_a.empty?
128
+ Packer.use do |packer|
129
+ packer.write_array_header(ctx.length * 2)
130
+ ctx.each do |c|
131
+ packer.write(c.id)
132
+ Value.of(c.value).pack(packer)
133
+ end
134
+ return packer.bytes
135
+ end
136
+ end
137
+ nil
138
+ end
139
+
140
+ def ==(other)
141
+ self.id == other.id && self.value == other.value
142
+ end
110
143
 
144
+ ##
145
+ # decodes the base64 encoded messagepack byte array
146
+ # and converts it to an array of Context.
147
+ def self.from_bytes(buf)
148
+ list = nil
149
+ Unpacker.use do |unpacker|
150
+ list = unpacker.unpack(buf)
151
+ end
152
+
153
+ unless list.length % 2 == 0
154
+ raise Exceptions::Aerospike.new(Aerospike::ResultCode::PARAMETER_ERROR, "Invalid buffer")
155
+ end
156
+
157
+ list.each_slice(2).map { |id, value| Context.new(id, value) }
158
+ end
159
+
160
+ ##
161
+ # Encodes the context array to messagepack and then encodes
162
+ # the resulting byte array to base64.
163
+ def self.base64(ctx)
164
+ unless ctx.to_a.empty?
165
+ data = self.bytes(ctx)
166
+ return Base64.strict_encode64(data).force_encoding("binary")
167
+ end
168
+ ""
169
+ end
170
+
171
+ ##
172
+ # Decodes the byte array to messagepack and then decodes
173
+ # the resulting byte array to an array of Context.
174
+ def self.from_base64(buf)
175
+ bytes = Base64.strict_decode64(buf)
176
+ self.from_bytes(bytes)
177
+ end
111
178
  end
112
179
  end
113
180
  end
@@ -17,8 +17,8 @@
17
17
  module Aerospike
18
18
  module CDT
19
19
  class MapPolicy
20
-
21
20
  attr_accessor :order, :write_mode, :flags
21
+ attr_accessor :item_command, :items_command, :attributes
22
22
 
23
23
  def initialize(order: nil, write_mode: nil, flags: nil)
24
24
  if write_mode && flags
@@ -28,10 +28,24 @@ module Aerospike
28
28
  @order = order || MapOrder::DEFAULT
29
29
  @write_mode = write_mode || MapWriteMode::DEFAULT
30
30
  @flags = flags || MapWriteFlags::DEFAULT
31
+ @attributes = order ? order[:attr] : 0
32
+
33
+ case @write_mode
34
+ when CDT::MapWriteMode::DEFAULT
35
+ @item_command = CDT::MapOperation::PUT
36
+ @items_command = CDT::MapOperation::PUT_ITEMS
37
+ when CDT::MapWriteMode::UPDATE_ONLY
38
+ @item_command = CDT::MapOperation::REPLACE
39
+ @items_command = CDT::MapOperation::REPLACE_ITEMS
40
+ when CDT::MapWriteMode::CREATE_ONLY
41
+ @item_command = CDT::MapOperation::ADD
42
+ @items_command = CDT::MapOperation::ADD_ITEMS
43
+ else
44
+ raise Exceptions.new(ResultCode::PARAMETER_ERROR, "invalid value for MapWriteMode #{write_mode}")
45
+ end
31
46
  end
32
47
 
33
48
  DEFAULT = MapPolicy.new
34
-
35
49
  end
36
50
  end
37
51
  end
@@ -69,10 +69,18 @@ module Aerospike
69
69
  # Return true if count > 0.
70
70
  EXISTS = 13
71
71
 
72
+ ##
73
+ # :private
74
+ #
75
+ # TODO: Should be like ListOperation and Implement InvertibleMapOperation
76
+ # Inverts meaning of map command and return values. For example:
77
+ # map_remove_by_key_range(bin_name, key_begin, key_end, MapReturnType::KEY | MapReturnType::INVERTED)
78
+ # With the INVERTED flag enabled, the keys outside of the specified key range will be removed and returned.
79
+ INVERTED = 0x10000
80
+
72
81
  ##
73
82
  # Default return type: NONE
74
83
  DEFAULT_RETURN_TYPE = NONE
75
-
76
84
  end
77
85
  end
78
86
  end
@@ -15,8 +15,8 @@
15
15
  # License for the specific language governing permissions and limitations under
16
16
  # the License.
17
17
 
18
- require 'digest'
19
- require 'base64'
18
+ require "digest"
19
+ require "base64"
20
20
 
21
21
  module Aerospike
22
22
 
@@ -36,7 +36,6 @@ module Aerospike
36
36
  # +:fail_if_not_connected+ set to true
37
37
 
38
38
  class Client
39
-
40
39
  attr_accessor :default_admin_policy
41
40
  attr_accessor :default_batch_policy
42
41
  attr_accessor :default_info_policy
@@ -48,8 +47,7 @@ module Aerospike
48
47
  attr_accessor :cluster
49
48
 
50
49
  def initialize(hosts = nil, policy: ClientPolicy.new, connect: true)
51
-
52
- hosts = ::Aerospike::Host::Parse.(hosts || ENV['AEROSPIKE_HOSTS'] || 'localhost')
50
+ hosts = ::Aerospike::Host::Parse.(hosts || ENV["AEROSPIKE_HOSTS"] || "localhost")
53
51
  policy = create_policy(policy, ClientPolicy)
54
52
  set_default_policies(policy.policies)
55
53
  @cluster = Cluster.new(policy, hosts)
@@ -249,7 +247,7 @@ module Aerospike
249
247
  end
250
248
 
251
249
  response = send_info_command(policy, str_cmd, node).upcase
252
- return if response == 'OK'
250
+ return if response == "OK"
253
251
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_ERROR, "Truncate failed: #{response}")
254
252
  end
255
253
 
@@ -386,7 +384,8 @@ module Aerospike
386
384
  def operate(key, operations, options = nil)
387
385
  policy = create_policy(options, OperatePolicy, default_operate_policy)
388
386
 
389
- command = OperateCommand.new(@cluster, policy, key, operations)
387
+ args = OperateArgs.new(cluster, policy, default_write_policy, default_operate_policy, key, operations)
388
+ command = OperateCommand.new(@cluster, key, args)
390
389
  execute_command(command)
391
390
  command.record
392
391
  end
@@ -415,7 +414,7 @@ module Aerospike
415
414
  def register_udf(udf_body, server_path, language, options = nil)
416
415
  policy = create_policy(options, Policy, default_info_policy)
417
416
 
418
- content = Base64.strict_encode64(udf_body).force_encoding('binary')
417
+ content = Base64.strict_encode64(udf_body).force_encoding("binary")
419
418
  str_cmd = "udf-put:filename=#{server_path};content=#{content};"
420
419
  str_cmd << "content-len=#{content.length};udf-type=#{language};"
421
420
 
@@ -424,15 +423,15 @@ module Aerospike
424
423
 
425
424
  res = {}
426
425
  response_map.each do |k, response|
427
- vals = response.to_s.split(';')
426
+ vals = response.to_s.split(";")
428
427
  vals.each do |pair|
429
428
  k, v = pair.split("=", 2)
430
429
  res[k] = v
431
430
  end
432
431
  end
433
432
 
434
- if res['error']
435
- raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res['error']}\nFile: #{res['file']}\nLine: #{res['line']}\nMessage: #{res['message']}")
433
+ if res["error"]
434
+ raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res["error"]}\nFile: #{res["file"]}\nLine: #{res["line"]}\nMessage: #{res["message"]}")
436
435
  end
437
436
 
438
437
  UdfRegisterTask.new(@cluster, server_path)
@@ -454,7 +453,7 @@ module Aerospike
454
453
  response_map = @cluster.request_info(policy, str_cmd)
455
454
  _, response = response_map.first
456
455
 
457
- if response == 'ok'
456
+ if response == "ok"
458
457
  UdfRemoveTask.new(@cluster, udf_name)
459
458
  else
460
459
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_ERROR, response)
@@ -466,27 +465,27 @@ module Aerospike
466
465
  def list_udf(options = nil)
467
466
  policy = create_policy(options, Policy, default_info_policy)
468
467
 
469
- str_cmd = 'udf-list'
468
+ str_cmd = "udf-list"
470
469
 
471
470
  # Send command to one node. That node will distribute it to other nodes.
472
471
  response_map = @cluster.request_info(policy, str_cmd)
473
472
  _, response = response_map.first
474
473
 
475
- vals = response.split(';')
474
+ vals = response.split(";")
476
475
 
477
476
  vals.map do |udf_info|
478
- next if udf_info.strip! == ''
477
+ next if udf_info.strip! == ""
479
478
 
480
- udf_parts = udf_info.split(',')
479
+ udf_parts = udf_info.split(",")
481
480
  udf = UDF.new
482
481
  udf_parts.each do |values|
483
- k, v = values.split('=', 2)
482
+ k, v = values.split("=", 2)
484
483
  case k
485
- when 'filename'
484
+ when "filename"
486
485
  udf.filename = v
487
- when 'hash'
486
+ when "hash"
488
487
  udf.hash = v
489
- when 'type'
488
+ when "type"
490
489
  udf.language = v
491
490
  end
492
491
  end
@@ -501,7 +500,7 @@ module Aerospike
501
500
  # udf file = <server udf dir>/<package name>.lua
502
501
  #
503
502
  # This method is only supported by Aerospike 3 servers.
504
- def execute_udf(key, package_name, function_name, args=[], options = nil)
503
+ def execute_udf(key, package_name, function_name, args = [], options = nil)
505
504
  policy = create_policy(options, WritePolicy, default_write_policy)
506
505
 
507
506
  command = ExecuteCommand.new(@cluster, policy, key, package_name, function_name, args)
@@ -514,10 +513,10 @@ module Aerospike
514
513
  result_map = record.bins
515
514
 
516
515
  # User defined functions don't have to return a value.
517
- key, obj = result_map.detect{ |k, _| k.include?('SUCCESS') }
516
+ key, obj = result_map.detect { |k, _| k.include?("SUCCESS") }
518
517
  return obj if key
519
518
 
520
- key, obj = result_map.detect{ |k, _| k.include?('FAILURE') }
519
+ key, obj = result_map.detect { |k, _| k.include?("FAILURE") }
521
520
  message = key ? obj.to_s : "Invalid UDF return value"
522
521
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::UDF_BAD_RESPONSE, message)
523
522
  end
@@ -530,7 +529,7 @@ module Aerospike
530
529
  #
531
530
  # This method is only supported by Aerospike 3 servers.
532
531
  # If the policy is nil, the default relevant policy will be used.
533
- def execute_udf_on_query(statement, package_name, function_name, function_args=[], options = nil)
532
+ def execute_udf_on_query(statement, package_name, function_name, function_args = [], options = nil)
534
533
  policy = create_policy(options, QueryPolicy, default_query_policy)
535
534
 
536
535
  nodes = @cluster.nodes
@@ -559,7 +558,6 @@ module Aerospike
559
558
  ExecuteTask.new(@cluster, statement)
560
559
  end
561
560
 
562
-
563
561
  # Create secondary index.
564
562
  # This asynchronous server call will return before command is complete.
565
563
  # The user can optionally wait for command completion by using the returned
@@ -568,7 +566,8 @@ module Aerospike
568
566
  # This method is only supported by Aerospike 3 servers.
569
567
  # index_type should be :string, :numeric or :geo2dsphere (requires server version 3.7 or later)
570
568
  # collection_type should be :list, :mapkeys or :mapvalues
571
- def create_index(namespace, set_name, index_name, bin_name, index_type, collection_type = nil, options = nil)
569
+ # ctx is an optional list of context. Supported on server v6.1+.
570
+ def create_index(namespace, set_name, index_name, bin_name, index_type, collection_type = nil, options = nil, ctx: nil)
572
571
  if options.nil? && collection_type.is_a?(Hash)
573
572
  options, collection_type = collection_type, nil
574
573
  end
@@ -577,18 +576,19 @@ module Aerospike
577
576
  str_cmd = "sindex-create:ns=#{namespace}"
578
577
  str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
579
578
  str_cmd << ";indexname=#{index_name};numbins=1"
579
+ str_cmd << ";context=#{CDT::Context.base64(ctx)}" unless ctx.to_a.empty?
580
580
  str_cmd << ";indextype=#{collection_type.to_s.upcase}" if collection_type
581
581
  str_cmd << ";indexdata=#{bin_name},#{index_type.to_s.upcase}"
582
582
  str_cmd << ";priority=normal"
583
583
 
584
584
  # Send index command to one node. That node will distribute the command to other nodes.
585
585
  response = send_info_command(policy, str_cmd).upcase
586
- if response == 'OK'
586
+ if response == "OK"
587
587
  # Return task that could optionally be polled for completion.
588
588
  return IndexTask.new(@cluster, namespace, index_name)
589
589
  end
590
590
 
591
- if response.start_with?('FAIL:200')
591
+ if response.start_with?("FAIL:200")
592
592
  # Index has already been created. Do not need to poll for completion.
593
593
  return IndexTask.new(@cluster, namespace, index_name, true)
594
594
  end
@@ -607,10 +607,10 @@ module Aerospike
607
607
 
608
608
  # Send index command to one node. That node will distribute the command to other nodes.
609
609
  response = send_info_command(policy, str_cmd).upcase
610
- return if response == 'OK'
610
+ return if response == "OK"
611
611
 
612
612
  # Index did not previously exist. Return without error.
613
- return if response.start_with?('FAIL:201')
613
+ return if response.start_with?("FAIL:201")
614
614
 
615
615
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INDEX_GENERIC, "Drop index failed: #{response}")
616
616
  end
@@ -966,7 +966,5 @@ module Aerospike
966
966
 
967
967
  threads.each(&:join)
968
968
  end
969
-
970
969
  end # class
971
-
972
970
  end # module