aerospike 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 Aerospike, Inc.
3
+ #
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
7
+ #
8
+ # http:#www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # 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.
15
+
16
+ require 'aerospike/policy/batch_policy'
17
+
18
+ module Aerospike
19
+
20
+ # Container object for scan policy command.
21
+ class QueryPolicy < BatchPolicy
22
+
23
+ def initialize()
24
+ super()
25
+
26
+ @max_retries = 0
27
+
28
+ self
29
+ end
30
+
31
+ end # class
32
+
33
+ end # module
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 Aerospike, Inc.
3
+ #
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
7
+ #
8
+ # http:#www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # 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.
15
+
16
+ require 'aerospike/policy/batch_policy'
17
+
18
+ module Aerospike
19
+
20
+ # Container object for scan policy command.
21
+ class ScanPolicy < BatchPolicy
22
+
23
+ attr_accessor :scan_percent, :concurrent_nodes,
24
+ :include_bin_data, :fail_on_cluster_change
25
+
26
+ def initialize(scan_percent=nil, concurrent_nodes=nil, include_bin_data=nil, fail_on_cluster_change=nil)
27
+ super()
28
+
29
+ @scan_percent = scan_percent || 100
30
+ @concurrent_nodes = concurrent_nodes.nil? ? true : concurrent_nodes
31
+ @include_bin_data = include_bin_data.nil? ? true : include_bin_data
32
+ @fail_on_cluster_change = fail_on_cluster_change.nil? ? true : fail_on_cluster_change
33
+
34
+ @max_retries = 0
35
+
36
+ self
37
+ end
38
+
39
+ end # class
40
+
41
+ end # module
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 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
+ module Aerospike
18
+
19
+ class Filter
20
+
21
+ def self.Equal(bin_name, value)
22
+ Filter.new(bin_name, value, value)
23
+ end
24
+
25
+ def self.Range(bin_name, from, to)
26
+ Filter.new(bin_name, from, to)
27
+ end
28
+
29
+ def estimate_size
30
+ return @name.bytesize + @begin.estimate_size + @end.estimate_size + 10
31
+ end
32
+
33
+ def write(buf, offset)
34
+ # Write name.
35
+ len = buf.write_binary(@name, offset+1)
36
+ buf.write_byte(len, offset)
37
+ offset += len + 1
38
+
39
+ # Write particle type.
40
+ buf.write_byte(@begin.type, offset)
41
+ offset+=1
42
+
43
+ # Write filter begin.
44
+ len = @begin.write(buf, offset+4)
45
+ buf.write_int32(len, offset)
46
+ offset += len + 4
47
+
48
+ # Write filter end.
49
+ len = @end.write(buf, offset+4)
50
+ buf.write_int32(len, offset)
51
+ offset += len + 4
52
+
53
+ offset
54
+ end
55
+
56
+ private
57
+
58
+ def initialize(bin_name, begin_value, end_value)
59
+ @name = bin_name
60
+ @begin = Aerospike::Value.of(begin_value)
61
+ @end = Aerospike::Value.of(end_value)
62
+ end
63
+
64
+ end # class
65
+
66
+ end
@@ -0,0 +1,200 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 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
+ require 'aerospike/query/stream_command'
18
+ require 'aerospike/query/recordset'
19
+
20
+ module Aerospike
21
+
22
+ private
23
+
24
+ class QueryCommand < StreamCommand
25
+
26
+ def initialize(node, policy, statement, recordset)
27
+ super(node)
28
+
29
+ @policy = policy
30
+ @statement = statement
31
+ @recordset = recordset
32
+ end
33
+
34
+ def write_buffer
35
+ fieldCount = 0
36
+ filterSize = 0
37
+ binNameSize = 0
38
+
39
+ begin_cmd
40
+
41
+ if @statement.namespace
42
+ @data_offset += @statement.namespace.bytesize + FIELD_HEADER_SIZE
43
+ fieldCount+=1
44
+ end
45
+
46
+ if @statement.index_name
47
+ @data_offset += @statement.index_name.bytesize + FIELD_HEADER_SIZE
48
+ fieldCount+=1
49
+ end
50
+
51
+ if @statement.set_name
52
+ @data_offset += @statement.set_name.bytesize + FIELD_HEADER_SIZE
53
+ fieldCount+=1
54
+ end
55
+
56
+ if @statement.filters && @statement.filters.length > 0
57
+ @data_offset += FIELD_HEADER_SIZE
58
+ filterSize+=1 # num filters
59
+
60
+ @statement.filters.each do |filter|
61
+ sz = filter.estimate_size
62
+ filterSize += sz
63
+ end
64
+ @data_offset += filterSize
65
+ fieldCount+=1
66
+ else
67
+ # Calling query with no filters is more efficiently handled by a primary index scan.
68
+ # Estimate scan options size.
69
+ @data_offset += (2 + FIELD_HEADER_SIZE)
70
+ fieldCount+=1
71
+ end
72
+
73
+ if @statement.bin_names && @statement.bin_names.length > 0
74
+ @data_offset += FIELD_HEADER_SIZE
75
+ binNameSize+=1 # num bin names
76
+
77
+ @statement.bin_names.each do |bin_name|
78
+ binNameSize += bin_name.bytesize + 1 #OPERATION_HEADER_SIZE
79
+ end
80
+ @data_offset += binNameSize
81
+ fieldCount+=1
82
+ end
83
+
84
+ @statement.task_id = Time.now.to_i + Time.usec if @statement.task_id == 0
85
+
86
+ @data_offset += 8 + FIELD_HEADER_SIZE
87
+ fieldCount+=1
88
+
89
+ if @statement.function_name
90
+ @data_offset += FIELD_HEADER_SIZE + 1 # udf type
91
+ @data_offset += @statement.package_name.bytesize + FIELD_HEADER_SIZE
92
+ @data_offset += @statement.function_name.bytesize + FIELD_HEADER_SIZE
93
+
94
+ if @statement.function_args && @statement.function_args.length > 0
95
+ functionArgBuffer = Value.of(@statement.function_args).bytes
96
+ else
97
+ functionArgBuffer = 0.ord
98
+ end
99
+ @data_offset += FIELD_HEADER_SIZE + functionArgBuffer.bytesize
100
+ fieldCount += 4
101
+ end
102
+
103
+ if @statement.filters.nil? || @statement.filters.empty?
104
+ if @statement.bin_names && @statement.bin_names.length > 0
105
+ @statement.bin_names.each do |bin_name|
106
+ estimate_operation_size_for_bin_name(bin_name)
107
+ end
108
+ end
109
+ end
110
+
111
+ size_buffer
112
+
113
+ readAttr = INFO1_READ
114
+ operation_count = (@statement.filters.to_a.length == 0 && @statement.bin_names.to_a.length == 0) ? @statement.bin_names.length : 0
115
+
116
+ write_header(readAttr, 0, fieldCount, operation_count)
117
+
118
+ if @statement.namespace
119
+ write_field_string(@statement.namespace, Aerospike::FieldType::NAMESPACE)
120
+ end
121
+
122
+ unless @statement.index_name.nil?
123
+ write_field_string(@statement.index_name, Aerospike::FieldType::INDEX_NAME)
124
+ end
125
+
126
+ if @statement.set_name
127
+ write_field_string(@statement.set_name, Aerospike::FieldType::TABLE)
128
+ end
129
+
130
+ if @statement.filters && @statement.filters.length > 0
131
+ write_field_header(filterSize, Aerospike::FieldType::INDEX_RANGE)
132
+ @data_buffer.write_byte(@statement.filters.length, @data_offset)
133
+ @data_offset+=1
134
+
135
+ @statement.filters.each do |filter|
136
+ @data_offset = filter.write(@data_buffer, @data_offset)
137
+ end
138
+
139
+ # Query bin names are specified as a field (Scan bin names are specified later as operations)
140
+ if @statement.bin_names && @statement.bin_names.length > 0
141
+ write_field_header(binNameSize, Aerospike::FieldType::QUERY_BINLIST)
142
+ @data_buffer.write_byte(@statement.bin_names.length, @data_offset)
143
+ @data_offset += 1
144
+
145
+ @statement.bin_names.each do |bin_name|
146
+ len = @data_buffer.write_binary(bin_name, @data_offset + 1)
147
+ @data_buffer.write_byte(len, @data_offset)
148
+ @data_offset += len + 1;
149
+ end
150
+ end
151
+ else
152
+ # Calling query with no filters is more efficiently handled by a primary index scan.
153
+ write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
154
+ priority = @policy.priority.ord
155
+ priority = priority << 4
156
+ @data_buffer.write_byte(priority, @data_offset)
157
+ @data_offset+=1
158
+ @data_buffer.write_byte(100.ord, @data_offset)
159
+ @data_offset+=1
160
+ end
161
+
162
+ if @statement.bin_names && @statement.bin_names.length > 0
163
+ write_field_header(binNameSize, Aerospike::FieldType::QUERY_BINLIST)
164
+ @data_buffer.write_byte(@statement.bin_names.length, @data_offset)
165
+ @data_offset+=1
166
+
167
+ @statement.bin_names.each do |bin_name|
168
+ len = @data_buffer.write_binary(bin_name, @data_offset + 1)
169
+ @data_buffer.write_byte(len, @data_offset)
170
+ @data_offset += len + 1
171
+ end
172
+ end
173
+
174
+ write_field_header(8, Aerospike::FieldType::TRAN_ID)
175
+ @data_buffer.write_int64(@statement.task_id, @data_offset)
176
+ @data_offset += 8
177
+
178
+ if @statement.function_name
179
+ write_field_header(1, Aerospike::FieldType::UDF_OP)
180
+ if @statement.return_data
181
+ @data_buffer.write_byte(1, @data_offset)
182
+ @data_offset+=1
183
+ else
184
+ @data_buffer.write_byte(2, @data_offset)
185
+ @data_offset+=1
186
+ end
187
+
188
+ write_field_string(@statement.package_name, Aerospike::FieldType::UDF_PACKAGE_NAME)
189
+ write_field_string(@statement.function_name, Aerospike::FieldType::UDF_FUNCTION)
190
+ write_field_bytes(functionArgBuffer, Aerospike::FieldType::UDF_ARGLIST)
191
+ end
192
+
193
+ end_cmd
194
+
195
+ return nil
196
+ end
197
+
198
+ end # class
199
+
200
+ end # module
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 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
+ module Aerospike
18
+
19
+ # Recordset implements a queue for a producer-consumer pattern
20
+ # a producer is a thread that fetches records from one node and puts them on this queue
21
+ # a consumer fetches records from this queue
22
+ # so the production and the consumptoin are decoupled
23
+ # there can be an unlimited count of producer threads and consumer threads
24
+ class Recordset
25
+
26
+ attr_reader :records
27
+
28
+ def initialize(queue_size = 5000, thread_count = 1, type)
29
+ queue_size = thread_count if queue_size < thread_count
30
+ @records = SizedQueue.new(queue_size)
31
+
32
+ # holds the count of active threads.
33
+ # when it reaches zero it means the whole operations of fetching records from server nodes is finished
34
+ @active_threads = Atomic.new(thread_count)
35
+
36
+ # operation cancelled by user or an exception occured in one of the threads
37
+ @cancelled = Atomic.new(false)
38
+
39
+ # saves the exception that occurred inside one of the threads to reraise it in the main thread
40
+ # and also is a signal to terminate other threads as the whole operation is assumed as failed
41
+ @thread_exception = Atomic.new(nil)
42
+
43
+ # type of the operation. it is either :scan or :query
44
+ @type = type
45
+ end
46
+
47
+ # fetches and return the first record from the queue
48
+ # if the operation is not finished and the queue is empty it blocks and waits for new records
49
+ # it sets the exception if it reaches the EOF mark, and returns nil
50
+ # EOF means the operation has finished and no more records are comming from server nodes
51
+ # it re-raises the exception occurred in threads, or which was set after reaching the EOF in the previous call
52
+ def next_record
53
+ raise @thread_exception.get unless @thread_exception.get.nil?
54
+
55
+ r = @records.deq
56
+
57
+ set_exception if r.nil?
58
+
59
+ r
60
+ end
61
+
62
+ # recordset is active unless it is cancelled by the user or an exception has occurred in of threads
63
+ def active?
64
+ !@cancelled.get
65
+ end
66
+
67
+ # this is called by working threads to signal their job is finished
68
+ # it decreases the count of active threads and puts an EOF on queue when all threads are finished
69
+ def thread_finished
70
+ @active_threads.update do |v|
71
+ v -= 1
72
+ @records.enq(nil) if v == 0
73
+ v
74
+ end
75
+ end
76
+
77
+ # this is called by a thread who faced an exception to singnal to terminate the whole operation
78
+ # it also may be called by the user to terminate the command in the middle of fetching records from server nodes
79
+ # it clears the queue so that if any threads are waiting for the queue get unblocked and find out about the cancellation
80
+ def cancel(expn=nil)
81
+ set_exception(expn)
82
+ @cancelled.set(true)
83
+ @records.clear
84
+ end
85
+
86
+ # fetches and returns all the records from the queue until the whole operation is finished and it reaches an EOF mark
87
+ # calling cancel inside the each block raises an exception to signal other consumer threads
88
+ def each(&block)
89
+ r = true
90
+ while r
91
+ r = next_record
92
+ # nil means EOF
93
+ unless r.nil?
94
+ block.call(r)
95
+ else
96
+ # reached the EOF
97
+ break
98
+ end
99
+ end
100
+ end
101
+
102
+ # the command is a scan if there are no filters applied otherwise it is a query
103
+ def is_scan?
104
+ @filters.nil? || @filters.empty?
105
+ end
106
+
107
+ private
108
+
109
+ def set_exception(expn=nil)
110
+ expn ||= (@type == :scan ? SCAN_TERMINATED_EXCEPTION : QUERY_TERMINATED_EXCEPTION)
111
+ @thread_exception.set(expn)
112
+ end
113
+
114
+ end
115
+
116
+ private
117
+
118
+ SCAN_TERMINATED_EXCEPTION = Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SCAN_TERMINATED)
119
+ QUERY_TERMINATED_EXCEPTION = Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SCAN_TERMINATED)
120
+
121
+ end