aerospike 2.25.0 → 2.27.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/aerospike/cdt/context.rb +136 -69
- data/lib/aerospike/client.rb +57 -3
- data/lib/aerospike/command/command.rb +251 -4
- data/lib/aerospike/policy/policy.rb +11 -1
- data/lib/aerospike/policy/write_policy.rb +8 -3
- data/lib/aerospike/query/filter.rb +44 -32
- data/lib/aerospike/query/query_partition_command.rb +9 -11
- data/lib/aerospike/query/server_command.rb +60 -0
- data/lib/aerospike/query/statement.rb +31 -18
- data/lib/aerospike/record.rb +15 -1
- data/lib/aerospike/version.rb +1 -1
- data/lib/aerospike.rb +1 -0
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fe67950bfa737ce26a8a0e823cd84424219c6ce41720e0202ca93d4dcab2c1d
|
4
|
+
data.tar.gz: 83976d88565599f00136967bd86fe832a88783518c51be2789c1463fa06e795e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e018d80b673081cdbf229aa5c48dd7ebbeb9a127492cc04c651a4e56bab92d7764aba82ffb3e3783f6a6f34755ded66be58c3bf5a9e110be61c0c21e20128932
|
7
|
+
data.tar.gz: 8e02a4d37b620f838dde53b63d4af3fe20146905dd4f3a30c14f97a83453c69f0dccfbaf1f44a777bf4ab53e89583cc7a6e4343204e6749b1d4fb888f0a7200f
|
data/CHANGELOG.md
CHANGED
@@ -2,10 +2,24 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [2.27.0] 2023-05-18
|
6
|
+
- **New Features**
|
7
|
+
- [CLIENT-1176] Support write operations in background query
|
8
|
+
|
9
|
+
|
10
|
+
## [2.26.0] 2022-12-02
|
11
|
+
|
12
|
+
- **New Features**
|
13
|
+
- [CLIENT-1808] Support creating a secondary index on elements within a CDT using `Context`.
|
14
|
+
- [CLIENT-1991] Add base64 encoding methods to `Context`.
|
15
|
+
- [CLIENT-2007] Support using `Context` in query filters.
|
16
|
+
|
5
17
|
## [2.25.0] 2022-11-28
|
6
18
|
|
7
19
|
- **New Features**
|
8
20
|
|
21
|
+
- [CLIENT-1984] Support scan-show and query-show info commands.
|
22
|
+
|
9
23
|
- [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.
|
10
24
|
|
11
25
|
- Adds `Policy#filter_exp` and `Policy#fail_on_filtered_out`
|
@@ -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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
data/lib/aerospike/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2014-
|
1
|
+
# Copyright 2014-2023 Aerospike, Inc.
|
2
2
|
#
|
3
3
|
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
4
|
# license agreements.
|
@@ -225,7 +225,6 @@ module Aerospike
|
|
225
225
|
policy = create_policy(options, Policy, default_info_policy)
|
226
226
|
|
227
227
|
node = @cluster.random_node
|
228
|
-
conn = node.get_connection(policy.timeout)
|
229
228
|
|
230
229
|
if set_name && !set_name.to_s.strip.empty?
|
231
230
|
str_cmd = "truncate:namespace=#{namespace}"
|
@@ -566,7 +565,8 @@ module Aerospike
|
|
566
565
|
# This method is only supported by Aerospike 3 servers.
|
567
566
|
# index_type should be :string, :numeric or :geo2dsphere (requires server version 3.7 or later)
|
568
567
|
# collection_type should be :list, :mapkeys or :mapvalues
|
569
|
-
|
568
|
+
# ctx is an optional list of context. Supported on server v6.1+.
|
569
|
+
def create_index(namespace, set_name, index_name, bin_name, index_type, collection_type = nil, options = nil, ctx: nil)
|
570
570
|
if options.nil? && collection_type.is_a?(Hash)
|
571
571
|
options, collection_type = collection_type, nil
|
572
572
|
end
|
@@ -575,6 +575,7 @@ module Aerospike
|
|
575
575
|
str_cmd = "sindex-create:ns=#{namespace}"
|
576
576
|
str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
|
577
577
|
str_cmd << ";indexname=#{index_name};numbins=1"
|
578
|
+
str_cmd << ";context=#{CDT::Context.base64(ctx)}" unless ctx.to_a.empty?
|
578
579
|
str_cmd << ";indextype=#{collection_type.to_s.upcase}" if collection_type
|
579
580
|
str_cmd << ";indexdata=#{bin_name},#{index_type.to_s.upcase}"
|
580
581
|
str_cmd << ";priority=normal"
|
@@ -729,6 +730,59 @@ module Aerospike
|
|
729
730
|
query_partitions(Aerospike::PartitionFilter.all, statement, options)
|
730
731
|
end
|
731
732
|
|
733
|
+
#----------------------------------------------------------
|
734
|
+
# Query/Execute (Supported by Aerospike 3+ servers only)
|
735
|
+
#----------------------------------------------------------
|
736
|
+
|
737
|
+
# QueryExecute applies operations on records that match the statement filter.
|
738
|
+
# Records are not returned to the client.
|
739
|
+
# This asynchronous server call will return before the command is complete.
|
740
|
+
# The user can optionally wait for command completion by using the returned
|
741
|
+
# ExecuteTask instance.
|
742
|
+
#
|
743
|
+
# This method is only supported by Aerospike 3+ servers.
|
744
|
+
# If the policy is nil, the default relevant policy will be used.
|
745
|
+
#
|
746
|
+
# @param statement [Aerospike::Statement] The query or batch read statement.
|
747
|
+
# @param operations [Array<Aerospike::Operation>] An optional list of operations.
|
748
|
+
# @param options [Hash] An optional hash of policy options.
|
749
|
+
# @return [Aerospike::ExecuteTask] An ExecuteTask instance that can be used to wait for command completion.
|
750
|
+
#
|
751
|
+
# @raise [Aerospike::Exceptions::Aerospike] if an error occurs during the operation.
|
752
|
+
def query_execute(statement, operations = [], options = nil)
|
753
|
+
policy = create_policy(options, WritePolicy, default_write_policy)
|
754
|
+
|
755
|
+
if statement.nil?
|
756
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_COMMAND, "Query failed of invalid statement.")
|
757
|
+
end
|
758
|
+
|
759
|
+
statement = statement.clone
|
760
|
+
unless operations.empty?
|
761
|
+
statement.operations = operations
|
762
|
+
end
|
763
|
+
|
764
|
+
task_id = statement.task_id
|
765
|
+
nodes = @cluster.nodes
|
766
|
+
if nodes.empty?
|
767
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Query failed because cluster is empty.")
|
768
|
+
end
|
769
|
+
|
770
|
+
# Use a thread per node
|
771
|
+
nodes.each do |node|
|
772
|
+
Thread.new do
|
773
|
+
Thread.current.abort_on_exception = true
|
774
|
+
begin
|
775
|
+
command = ServerCommand.new(@cluster, node, policy, statement, true, task_id)
|
776
|
+
execute_command(command)
|
777
|
+
rescue => e
|
778
|
+
Aerospike.logger.error(e)
|
779
|
+
raise e
|
780
|
+
end
|
781
|
+
end
|
782
|
+
end
|
783
|
+
ExecuteTask.new(@cluster, statement)
|
784
|
+
end
|
785
|
+
|
732
786
|
#-------------------------------------------------------
|
733
787
|
# User administration
|
734
788
|
#-------------------------------------------------------
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2014-
|
1
|
+
# Copyright 2014-2024 Aerospike, Inc.
|
2
2
|
#
|
3
3
|
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
4
|
# license agreements.
|
@@ -465,6 +465,254 @@ module Aerospike
|
|
465
465
|
end_cmd
|
466
466
|
end
|
467
467
|
|
468
|
+
def set_query(policy, statement, background, node_partitions)
|
469
|
+
function_arg_buffer = nil
|
470
|
+
field_count = 0
|
471
|
+
filter_size = 0
|
472
|
+
|
473
|
+
begin_cmd
|
474
|
+
|
475
|
+
if statement.namespace
|
476
|
+
@data_offset += statement.namespace.bytesize + FIELD_HEADER_SIZE
|
477
|
+
field_count += 1
|
478
|
+
end
|
479
|
+
|
480
|
+
if statement.set_name
|
481
|
+
@data_offset += statement.set_name.bytesize + FIELD_HEADER_SIZE
|
482
|
+
field_count += 1
|
483
|
+
end
|
484
|
+
|
485
|
+
# Estimate recordsPerSecond field size. This field is used in new servers and not used
|
486
|
+
# (but harmless to add) in old servers.
|
487
|
+
if statement.records_per_second > 0
|
488
|
+
@data_offset += 4 + FIELD_HEADER_SIZE
|
489
|
+
field_count += 1
|
490
|
+
end
|
491
|
+
|
492
|
+
# Estimate socket timeout field size. This field is used in new servers and not used
|
493
|
+
# (but harmless to add) in old servers.
|
494
|
+
@data_offset += 4 + FIELD_HEADER_SIZE
|
495
|
+
field_count += 1
|
496
|
+
|
497
|
+
# Estimate task_id field.
|
498
|
+
@data_offset += 8 + FIELD_HEADER_SIZE
|
499
|
+
field_count += 1
|
500
|
+
|
501
|
+
filter = statement.filters[0]
|
502
|
+
bin_names = statement.bin_names
|
503
|
+
packed_ctx = nil
|
504
|
+
|
505
|
+
if filter
|
506
|
+
col_type = filter.collection_type
|
507
|
+
|
508
|
+
# Estimate INDEX_TYPE field.
|
509
|
+
if col_type > 0
|
510
|
+
@data_offset += FIELD_HEADER_SIZE + 1
|
511
|
+
field_count += 1
|
512
|
+
end
|
513
|
+
|
514
|
+
# Estimate INDEX_RANGE field.
|
515
|
+
@data_offset += FIELD_HEADER_SIZE
|
516
|
+
filter_size += 1 # num filters
|
517
|
+
filter_size += filter.estimate_size
|
518
|
+
|
519
|
+
@data_offset += filter_size
|
520
|
+
field_count += 1
|
521
|
+
|
522
|
+
packed_ctx = filter.packed_ctx
|
523
|
+
if packed_ctx
|
524
|
+
@data_offset += FIELD_HEADER_SIZE + packed_ctx.length
|
525
|
+
field_count += 1
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
statement.set_task_id
|
530
|
+
predexp = policy.predexp || statement.predexp
|
531
|
+
|
532
|
+
if predexp
|
533
|
+
@data_offset += FIELD_HEADER_SIZE
|
534
|
+
pred_size = Aerospike::PredExp.estimate_size(predexp)
|
535
|
+
@data_offset += pred_size
|
536
|
+
field_count += 1
|
537
|
+
end
|
538
|
+
|
539
|
+
unless policy.filter_exp.nil?
|
540
|
+
exp_size = estimate_expression_size(policy.filter_exp)
|
541
|
+
field_count += 1 if exp_size > 0
|
542
|
+
end
|
543
|
+
|
544
|
+
# Estimate aggregation/background function size.
|
545
|
+
if statement.function_name
|
546
|
+
@data_offset += FIELD_HEADER_SIZE + 1 # udf type
|
547
|
+
@data_offset += statement.package_name.bytesize + FIELD_HEADER_SIZE
|
548
|
+
@data_offset += statement.function_name.bytesize + FIELD_HEADER_SIZE
|
549
|
+
|
550
|
+
function_arg_buffer = ""
|
551
|
+
if statement.function_args && statement.function_args.length > 0
|
552
|
+
function_arg_buffer = Value.of(statement.function_args).to_bytes
|
553
|
+
end
|
554
|
+
@data_offset += FIELD_HEADER_SIZE + function_arg_buffer.bytesize
|
555
|
+
field_count += 4
|
556
|
+
end
|
557
|
+
|
558
|
+
max_records = 0
|
559
|
+
parts_full_size = 0
|
560
|
+
parts_partial_digest_size = 0
|
561
|
+
parts_partial_bval_size = 0
|
562
|
+
|
563
|
+
unless node_partitions.nil?
|
564
|
+
parts_full_size = node_partitions.parts_full.length * 2
|
565
|
+
parts_partial_digest_size = node_partitions.parts_partial.length * 20
|
566
|
+
|
567
|
+
unless filter.nil?
|
568
|
+
parts_partial_bval_size = node_partitions.parts_partial.length * 8
|
569
|
+
end
|
570
|
+
max_records = node_partitions.record_max
|
571
|
+
end
|
572
|
+
|
573
|
+
if parts_full_size > 0
|
574
|
+
@data_offset += parts_full_size + FIELD_HEADER_SIZE
|
575
|
+
field_count += 1
|
576
|
+
end
|
577
|
+
|
578
|
+
if parts_partial_digest_size > 0
|
579
|
+
@data_offset += parts_partial_digest_size + FIELD_HEADER_SIZE
|
580
|
+
field_count += 1
|
581
|
+
end
|
582
|
+
|
583
|
+
if parts_partial_bval_size > 0
|
584
|
+
@data_offset += parts_partial_bval_size + FIELD_HEADER_SIZE
|
585
|
+
field_count += 1
|
586
|
+
end
|
587
|
+
|
588
|
+
# Estimate max records field size. This field is used in new servers and not used
|
589
|
+
# (but harmless to add) in old servers.
|
590
|
+
if max_records > 0
|
591
|
+
@data_offset += 8 + FIELD_HEADER_SIZE
|
592
|
+
field_count += 1
|
593
|
+
end
|
594
|
+
|
595
|
+
operations = statement.operations
|
596
|
+
operation_count = 0
|
597
|
+
|
598
|
+
if !operations.empty?
|
599
|
+
|
600
|
+
unless background
|
601
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::PARAMETER_ERROR)
|
602
|
+
end
|
603
|
+
|
604
|
+
operations.each do |operation|
|
605
|
+
estimate_operation_size_for_operation(operation)
|
606
|
+
end
|
607
|
+
operation_count = operations.size
|
608
|
+
elsif !bin_names.empty?
|
609
|
+
bin_names.each do |bin_name|
|
610
|
+
estimate_operation_size_for_bin_name(bin_name)
|
611
|
+
end
|
612
|
+
operation_count = bin_names.length
|
613
|
+
# Estimate size for selected bin names (query bin names already handled for old servers).
|
614
|
+
end
|
615
|
+
|
616
|
+
size_buffer
|
617
|
+
|
618
|
+
if background
|
619
|
+
write_header_with_policy(policy, 0, INFO2_WRITE, field_count, operation_count)
|
620
|
+
else
|
621
|
+
read_attr = INFO1_READ
|
622
|
+
read_attr |= INFO1_NOBINDATA unless policy.include_bin_data
|
623
|
+
read_attr |= INFO1_SHORT_QUERY if policy.short_query
|
624
|
+
write_header(policy, read_attr, 0, field_count, operation_count)
|
625
|
+
end
|
626
|
+
|
627
|
+
write_field_string(statement.namespace, FieldType::NAMESPACE) if statement.namespace
|
628
|
+
write_field_string(statement.set_name, FieldType::TABLE) if statement.set_name
|
629
|
+
|
630
|
+
# Write records per second.
|
631
|
+
write_field_int(statement.records_per_second, FieldType::RECORDS_PER_SECOND) if statement.records_per_second > 0
|
632
|
+
|
633
|
+
write_filter_exp(policy.filter_exp, exp_size)
|
634
|
+
|
635
|
+
# Write socket idle timeout.
|
636
|
+
write_field_int(policy.socket_timeout, FieldType::SOCKET_TIMEOUT)
|
637
|
+
|
638
|
+
# Write task_id field
|
639
|
+
write_field_int64(statement.task_id, FieldType::TRAN_ID)
|
640
|
+
|
641
|
+
unless predexp.nil?
|
642
|
+
write_field_header(pred_size, Aerospike::FieldType::PREDEXP)
|
643
|
+
@data_offset = Aerospike::PredExp.write(
|
644
|
+
predexp, @data_buffer, @data_offset
|
645
|
+
)
|
646
|
+
end
|
647
|
+
|
648
|
+
if filter
|
649
|
+
type = filter.collection_type
|
650
|
+
|
651
|
+
if type > 0
|
652
|
+
write_field_header(1, FieldType::INDEX_TYPE)
|
653
|
+
@data_offset += @data_buffer.write_byte(type, @data_offset)
|
654
|
+
end
|
655
|
+
|
656
|
+
write_field_header(filter_size, FieldType::INDEX_RANGE)
|
657
|
+
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
658
|
+
@data_offset = filter.write(@data_buffer, @data_offset)
|
659
|
+
|
660
|
+
if packed_ctx
|
661
|
+
write_field_header(packed_ctx.length, FieldType::INDEX_CONTEXT)
|
662
|
+
@data_offset += @data_buffer.write_binary(packed_ctx, @data_offset)
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
if statement.function_name
|
667
|
+
write_field_header(1, FieldType::UDF_OP)
|
668
|
+
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
669
|
+
write_field_string(statement.package_name, FieldType::UDF_PACKAGE_NAME)
|
670
|
+
write_field_string(statement.function_name, FieldType::UDF_FUNCTION)
|
671
|
+
write_field_string(function_arg_buffer, FieldType::UDF_ARGLIST)
|
672
|
+
end
|
673
|
+
|
674
|
+
if parts_full_size > 0
|
675
|
+
write_field_header(parts_full_size, FieldType::PID_ARRAY)
|
676
|
+
node_partitions.parts_full.each do |part|
|
677
|
+
@data_offset += @data_buffer.write_uint16_little_endian(part.id, @data_offset)
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
if parts_partial_digest_size > 0
|
682
|
+
write_field_header(parts_partial_digest_size, FieldType::DIGEST_ARRAY)
|
683
|
+
node_partitions.parts_partial.each do |part|
|
684
|
+
@data_offset += @data_buffer.write_binary(part.digest, @data_offset)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
if parts_partial_bval_size > 0
|
689
|
+
write_field_header(parts_partial_bval_size, FieldType::BVAL_ARRAY)
|
690
|
+
@node_partitions.parts_partial.each do |part|
|
691
|
+
@data_offset += @data_buffer.write_uint64_little_endian(part.bval, @data_offset)
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
if max_records > 0
|
696
|
+
write_field(max_records, FieldType::MAX_RECORDS)
|
697
|
+
end
|
698
|
+
|
699
|
+
if operations.empty?
|
700
|
+
if bin_names.empty?
|
701
|
+
bin_names.each do |bin_name|
|
702
|
+
write_operation_for_bin_name(bin_name, Operation::READ)
|
703
|
+
end
|
704
|
+
end
|
705
|
+
else
|
706
|
+
operations.each do |operation|
|
707
|
+
write_operation_for_operation(operation)
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
end_cmd
|
712
|
+
|
713
|
+
nil
|
714
|
+
end
|
715
|
+
|
468
716
|
def execute
|
469
717
|
iterations = 0
|
470
718
|
|
@@ -537,7 +785,7 @@ module Aerospike
|
|
537
785
|
parse_result
|
538
786
|
rescue => e
|
539
787
|
case e
|
540
|
-
|
788
|
+
# do not log the following exceptions
|
541
789
|
when Aerospike::Exceptions::ScanTerminated
|
542
790
|
when Aerospike::Exceptions::QueryTerminated
|
543
791
|
else
|
@@ -703,9 +951,8 @@ module Aerospike
|
|
703
951
|
read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
|
704
952
|
write_attr |= INFO2_DURABLE_DELETE if policy.durable_delete
|
705
953
|
read_attr |= INFO1_COMPRESS_RESPONSE if policy.use_compression
|
706
|
-
|
707
954
|
# Write all header data except total size which must be written last.
|
708
|
-
@data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message
|
955
|
+
@data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message header.length.
|
709
956
|
@data_buffer.write_byte(read_attr, 9)
|
710
957
|
@data_buffer.write_byte(write_attr, 10)
|
711
958
|
@data_buffer.write_byte(info_attr, 11)
|
@@ -22,7 +22,7 @@ module Aerospike
|
|
22
22
|
# Container object for client policy command.
|
23
23
|
class Policy
|
24
24
|
attr_accessor :filter_exp, :priority, :timeout, :max_retries, :sleep_between_retries, :consistency_level,
|
25
|
-
:predexp, :fail_on_filtered_out, :replica, :use_compression
|
25
|
+
:predexp, :fail_on_filtered_out, :replica, :use_compression, :socket_timeout
|
26
26
|
|
27
27
|
alias total_timeout timeout
|
28
28
|
alias total_timeout= timeout=
|
@@ -133,6 +133,16 @@ module Aerospike
|
|
133
133
|
# Duration to sleep between retries if a transaction fails and the
|
134
134
|
# timeout was not exceeded. Enter zero to skip sleep.
|
135
135
|
@sleep_between_retries = opt[:sleep_between_retries] || 0.5
|
136
|
+
|
137
|
+
# Determines network timeout for each attempt.
|
138
|
+
#
|
139
|
+
# If socket_timeout is not zero and socket_timeout is reached before an attempt completes,
|
140
|
+
# the Timeout above is checked. If Timeout is not exceeded, the transaction
|
141
|
+
# is retried. If both socket_timeout and Timeout are non-zero, socket_timeout must be less
|
142
|
+
# than or equal to Timeout, otherwise Timeout will also be used for socket_timeout.
|
143
|
+
#
|
144
|
+
# Default: 30s
|
145
|
+
@socket_timeout = opt[:socket_timeout] || 30000
|
136
146
|
end
|
137
147
|
end # class
|
138
148
|
end # module
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
# Copyright 2014-
|
2
|
+
# Copyright 2014-2023 Aerospike, Inc.
|
3
3
|
#
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
5
|
# you may not use this file except in compliance with the License.
|
@@ -24,8 +24,8 @@ module Aerospike
|
|
24
24
|
class WritePolicy < Policy
|
25
25
|
|
26
26
|
attr_accessor :record_exists_action, :generation_policy,
|
27
|
-
|
28
|
-
|
27
|
+
:generation, :ttl, :send_key, :commit_level,
|
28
|
+
:durable_delete
|
29
29
|
|
30
30
|
alias expiration ttl
|
31
31
|
alias expiration= ttl=
|
@@ -74,6 +74,11 @@ module Aerospike
|
|
74
74
|
# Valid for Aerospike Server Enterprise Edition 3.10+ only.
|
75
75
|
@durable_delete = opt.fetch(:durable_delete, false)
|
76
76
|
|
77
|
+
# Transaction timeout.
|
78
|
+
# This timeout is used to set the socket timeout and is also sent to the
|
79
|
+
# server along with the transaction in the wire protocol.
|
80
|
+
# Default for write policy is 1.
|
81
|
+
@timeout = opt[:timeout] || 1
|
77
82
|
self
|
78
83
|
end
|
79
84
|
|
@@ -15,39 +15,51 @@
|
|
15
15
|
# the License.
|
16
16
|
|
17
17
|
module Aerospike
|
18
|
-
|
19
18
|
class Filter
|
19
|
+
attr_reader :packed_ctx
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# open up the class to alias the class methods for naming consistency
|
22
|
+
class << self
|
23
|
+
def equal(bin_name, value, ctx: nil)
|
24
|
+
Filter.new(bin_name, value, value, nil, nil, ctx)
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
def contains(bin_name, value, col_type, ctx: nil)
|
28
|
+
Filter.new(bin_name, value, value, nil, col_type, ctx)
|
29
|
+
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
def range(bin_name, from, to, col_type = nil, ctx: nil)
|
32
|
+
Filter.new(bin_name, from, to, nil, col_type, ctx)
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def geo_within_geo_region(bin_name, region, col_type = nil, ctx: nil)
|
36
|
+
region = region.to_json
|
37
|
+
Filter.new(bin_name, region, region, ParticleType::GEOJSON, col_type, ctx)
|
38
|
+
end
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
def geo_within_radius(bin_name, lon, lat, radius_meter, col_type = nil, ctx: nil)
|
41
|
+
region = GeoJSON.new({ type: "AeroCircle", coordinates: [[lon, lat], radius_meter] })
|
42
|
+
geo_within_geo_region(bin_name, region, col_type, ctx: ctx)
|
43
|
+
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
def geo_contains_geo_point(bin_name, point, col_type = nil, ctx: nil)
|
46
|
+
point = point.to_json
|
47
|
+
Filter.new(bin_name, point, point, ParticleType::GEOJSON, col_type, ctx)
|
48
|
+
end
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
def geo_contains_point(bin_name, lon, lat, col_type = nil, ctx: nil)
|
51
|
+
point = GeoJSON.new({ type: "Point", coordinates: [lon, lat] })
|
52
|
+
geo_contains_geo_point(bin_name, point, col_type, ctx: ctx)
|
53
|
+
end
|
54
|
+
|
55
|
+
# alias the old names for compatibility
|
56
|
+
alias :Equal :equal
|
57
|
+
alias :Contains :contains
|
58
|
+
alias :Range :range
|
59
|
+
alias :geoWithinGeoJSONRegion :geo_within_geo_region
|
60
|
+
alias :geoWithinRadius :geo_within_radius
|
61
|
+
alias :geoContainsGeoJSONPoint :geo_contains_geo_point
|
62
|
+
alias :geoContainsPoint :geo_contains_point
|
51
63
|
end
|
52
64
|
|
53
65
|
def estimate_size
|
@@ -56,21 +68,21 @@ module Aerospike
|
|
56
68
|
|
57
69
|
def write(buf, offset)
|
58
70
|
# Write name.
|
59
|
-
len = buf.write_binary(@name, offset+1)
|
71
|
+
len = buf.write_binary(@name, offset + 1)
|
60
72
|
buf.write_byte(len, offset)
|
61
73
|
offset += len + 1
|
62
74
|
|
63
75
|
# Write particle type.
|
64
76
|
buf.write_byte(@val_type, offset)
|
65
|
-
offset+=1
|
77
|
+
offset += 1
|
66
78
|
|
67
79
|
# Write filter begin.
|
68
|
-
len = @begin.write(buf, offset+4)
|
80
|
+
len = @begin.write(buf, offset + 4)
|
69
81
|
buf.write_int32(len, offset)
|
70
82
|
offset += len + 4
|
71
83
|
|
72
84
|
# Write filter end.
|
73
|
-
len = @end.write(buf, offset+4)
|
85
|
+
len = @end.write(buf, offset + 4)
|
74
86
|
buf.write_int32(len, offset)
|
75
87
|
offset += len + 4
|
76
88
|
|
@@ -98,7 +110,7 @@ module Aerospike
|
|
98
110
|
|
99
111
|
private
|
100
112
|
|
101
|
-
def initialize(bin_name, begin_value, end_value, val_type = nil, col_type = nil)
|
113
|
+
def initialize(bin_name, begin_value, end_value, val_type = nil, col_type = nil, ctx = nil)
|
102
114
|
@name = bin_name
|
103
115
|
@begin = Aerospike::Value.of(begin_value)
|
104
116
|
@end = Aerospike::Value.of(end_value)
|
@@ -107,8 +119,8 @@ module Aerospike
|
|
107
119
|
# but in certain cases caller can override the type.
|
108
120
|
@val_type = val_type || @begin.type
|
109
121
|
@col_type = col_type
|
110
|
-
end
|
111
122
|
|
123
|
+
@packed_ctx = CDT::Context.bytes(ctx)
|
124
|
+
end
|
112
125
|
end # class
|
113
|
-
|
114
126
|
end
|
@@ -82,12 +82,11 @@ module Aerospike
|
|
82
82
|
@data_offset += filter_size
|
83
83
|
field_count += 1
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
# end
|
85
|
+
packed_ctx = filter.packed_ctx
|
86
|
+
if packed_ctx
|
87
|
+
@data_offset += FIELD_HEADER_SIZE + packed_ctx.length
|
88
|
+
field_count += 1
|
89
|
+
end
|
91
90
|
end
|
92
91
|
|
93
92
|
@statement.set_task_id
|
@@ -210,11 +209,10 @@ module Aerospike
|
|
210
209
|
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
211
210
|
@data_offset = filter.write(@data_buffer, @data_offset)
|
212
211
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
# end
|
212
|
+
if packed_ctx
|
213
|
+
write_field_header(packed_ctx.length, FieldType::INDEX_CONTEXT)
|
214
|
+
@data_offset += @data_buffer.write_binary(packed_ctx, @data_offset)
|
215
|
+
end
|
218
216
|
end
|
219
217
|
|
220
218
|
if @statement.function_name
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2023 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
|
+
# license agreements.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
8
|
+
# 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
|
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, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations under
|
15
|
+
# the License.
|
16
|
+
|
17
|
+
|
18
|
+
module Aerospike
|
19
|
+
class ServerCommand < MultiCommand
|
20
|
+
attr_accessor :statement, :task_id, :cluster, :write_policy, :background
|
21
|
+
|
22
|
+
def initialize(cluster, node, policy, statement, background, task_id)
|
23
|
+
super(node)
|
24
|
+
@statement = statement
|
25
|
+
@task_id = task_id
|
26
|
+
@cluster = cluster
|
27
|
+
@policy = policy
|
28
|
+
@background = background
|
29
|
+
end
|
30
|
+
|
31
|
+
def write?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def write_buffer
|
36
|
+
set_query(@policy, @statement, background, nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_row
|
40
|
+
field_count = @data_buffer.read_int16(18)
|
41
|
+
result_code = @data_buffer.read(5).ord & 0xFF
|
42
|
+
skip_key(field_count)
|
43
|
+
|
44
|
+
if result_code != 0
|
45
|
+
if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
raise Aerospike::Exceptions::Aerospike.new(result_code)
|
49
|
+
end
|
50
|
+
op_count = @data_buffer.read_int16(20)
|
51
|
+
if op_count <= 0
|
52
|
+
return Record.new(@node, key, bins, generation, expiration)
|
53
|
+
end
|
54
|
+
|
55
|
+
unless valid?
|
56
|
+
raise Aerospike::Exceptions::QueryTerminated
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
# Copyright 2014-
|
2
|
+
# Copyright 2014-2023 Aerospike, Inc.
|
3
3
|
#
|
4
4
|
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
5
|
# license agreements.
|
@@ -16,11 +16,14 @@
|
|
16
16
|
|
17
17
|
module Aerospike
|
18
18
|
|
19
|
+
# The Aerospike::Statement class represents a query or scan statement to be executed on the database.
|
20
|
+
# It provides a set of properties that define the query or scan, including namespace, set name, bin names,
|
21
|
+
# index name, filters, and operations.
|
19
22
|
class Statement
|
20
23
|
|
21
24
|
attr_accessor :namespace, :set_name, :index_name, :bin_names, :task_id
|
22
|
-
attr_accessor :filters, :package_name, :function_name, :function_args
|
23
|
-
attr_accessor :predexp, :return_data
|
25
|
+
attr_accessor :filters, :package_name, :function_name, :function_args, :operations
|
26
|
+
attr_accessor :predexp, :return_data, :records_per_second
|
24
27
|
|
25
28
|
def initialize(namespace, set_name, bin_names=[])
|
26
29
|
# Namespace determines query Namespace
|
@@ -56,6 +59,14 @@ module Aerospike
|
|
56
59
|
@package_name = nil
|
57
60
|
@function_name = nil
|
58
61
|
@function_args = nil
|
62
|
+
@operations = nil
|
63
|
+
|
64
|
+
|
65
|
+
# Limit returned records per second (rps) rate for each server.
|
66
|
+
# Will not apply rps limit if records_per_second is zero.
|
67
|
+
# Currently only applicable to a query without a defined filter (scan).
|
68
|
+
# Default is 0
|
69
|
+
@records_per_second = 0
|
59
70
|
|
60
71
|
# TaskId determines query task id. (Optional)
|
61
72
|
@task_id = rand(RAND_MAX)
|
@@ -64,33 +75,35 @@ module Aerospike
|
|
64
75
|
@return_data = true
|
65
76
|
end
|
66
77
|
|
67
|
-
|
78
|
+
def set_aggregate_function(package_name, function_name, function_args=[], return_data=true)
|
68
79
|
@package_name = package_name
|
69
80
|
@function_name = function_name
|
70
81
|
@function_args = function_args
|
71
82
|
@return_data = return_data
|
72
|
-
|
83
|
+
end
|
73
84
|
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
def is_scan?
|
86
|
+
return (filters.nil? || (filters.empty?))
|
87
|
+
end
|
77
88
|
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
def set_task_id
|
90
|
+
while @task_id == 0
|
91
|
+
@task_id = rand(RAND_MAX)
|
92
|
+
end
|
81
93
|
end
|
82
|
-
end
|
83
94
|
|
84
|
-
|
85
|
-
@task_id = rand(RAND_MAX)
|
86
|
-
while @task_id == 0
|
95
|
+
def reset_task_id
|
87
96
|
@task_id = rand(RAND_MAX)
|
97
|
+
while @task_id == 0
|
98
|
+
@task_id = rand(RAND_MAX)
|
99
|
+
end
|
88
100
|
end
|
89
|
-
end
|
90
101
|
|
91
|
-
private
|
92
102
|
|
93
|
-
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
RAND_MAX = 2**63 - 1
|
94
107
|
|
95
108
|
end # class
|
96
109
|
end
|
data/lib/aerospike/record.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2014-
|
1
|
+
# Copyright 2014-2023 Aerospike, Inc.
|
2
2
|
#
|
3
3
|
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
4
|
# license agreements.
|
@@ -33,6 +33,8 @@ module Aerospike
|
|
33
33
|
@node = node
|
34
34
|
end
|
35
35
|
|
36
|
+
|
37
|
+
|
36
38
|
def to_s
|
37
39
|
"key: `#{key}` bins: `#{bins}` generation: `#{generation}`, ttl: `#{ttl}`"
|
38
40
|
end
|
@@ -41,6 +43,18 @@ module Aerospike
|
|
41
43
|
|
42
44
|
CITRUSLEAF_EPOCH = 1262304000
|
43
45
|
|
46
|
+
# Arguments:
|
47
|
+
# value: the key to retrieve the value for
|
48
|
+
#
|
49
|
+
# Returns:
|
50
|
+
# the value of the specified key, or `nil` if `@bins` is `nil`
|
51
|
+
def get_value(value)
|
52
|
+
unless @bins.nil?
|
53
|
+
return @bins[value]
|
54
|
+
end
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
44
58
|
# Converts an absolute expiration time (in seconds from citrusleaf epoch)
|
45
59
|
# to relative time-to-live (TTL) in seconds
|
46
60
|
def expiration_to_ttl(secs_from_epoc)
|
data/lib/aerospike/version.rb
CHANGED
data/lib/aerospike.rb
CHANGED
@@ -169,6 +169,7 @@ require "aerospike/query/scan_executor"
|
|
169
169
|
require "aerospike/query/scan_partition_command"
|
170
170
|
require "aerospike/query/query_executor"
|
171
171
|
require "aerospike/query/query_partition_command"
|
172
|
+
require "aerospike/query/server_command"
|
172
173
|
|
173
174
|
require "aerospike/exp/exp"
|
174
175
|
require "aerospike/exp/exp_map"
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aerospike
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.27.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Khosrow Afroozeh
|
8
8
|
- Jan Hecking
|
9
|
-
|
9
|
+
- Sachin Venkatesha Murthy
|
10
|
+
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2023-05-18 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: msgpack
|
@@ -44,6 +45,7 @@ description: Official Aerospike Client for ruby. Access your Aerospike cluster w
|
|
44
45
|
email:
|
45
46
|
- khosrow@aerospike.com
|
46
47
|
- jhecking@aerospike.com
|
48
|
+
- smurthy@aerospike.com
|
47
49
|
executables: []
|
48
50
|
extensions: []
|
49
51
|
extra_rdoc_files: []
|
@@ -181,6 +183,7 @@ files:
|
|
181
183
|
- lib/aerospike/query/scan_command.rb
|
182
184
|
- lib/aerospike/query/scan_executor.rb
|
183
185
|
- lib/aerospike/query/scan_partition_command.rb
|
186
|
+
- lib/aerospike/query/server_command.rb
|
184
187
|
- lib/aerospike/query/statement.rb
|
185
188
|
- lib/aerospike/query/stream_command.rb
|
186
189
|
- lib/aerospike/record.rb
|
@@ -227,8 +230,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
227
230
|
- !ruby/object:Gem::Version
|
228
231
|
version: '0'
|
229
232
|
requirements: []
|
230
|
-
rubygems_version: 3.3.
|
231
|
-
signing_key:
|
233
|
+
rubygems_version: 3.3.3
|
234
|
+
signing_key:
|
232
235
|
specification_version: 4
|
233
236
|
summary: An Aerospike driver for Ruby.
|
234
237
|
test_files: []
|