aerospike 0.1.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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +0 -0
  3. data/LICENSE +203 -0
  4. data/README.md +123 -0
  5. data/lib/aerospike.rb +69 -0
  6. data/lib/aerospike/aerospike_exception.rb +111 -0
  7. data/lib/aerospike/bin.rb +46 -0
  8. data/lib/aerospike/client.rb +649 -0
  9. data/lib/aerospike/cluster/cluster.rb +537 -0
  10. data/lib/aerospike/cluster/connection.rb +113 -0
  11. data/lib/aerospike/cluster/node.rb +248 -0
  12. data/lib/aerospike/cluster/node_validator.rb +85 -0
  13. data/lib/aerospike/cluster/partition.rb +54 -0
  14. data/lib/aerospike/cluster/partition_tokenizer_new.rb +128 -0
  15. data/lib/aerospike/cluster/partition_tokenizer_old.rb +135 -0
  16. data/lib/aerospike/command/batch_command.rb +120 -0
  17. data/lib/aerospike/command/batch_command_exists.rb +93 -0
  18. data/lib/aerospike/command/batch_command_get.rb +150 -0
  19. data/lib/aerospike/command/batch_item.rb +69 -0
  20. data/lib/aerospike/command/batch_node.rb +82 -0
  21. data/lib/aerospike/command/command.rb +680 -0
  22. data/lib/aerospike/command/delete_command.rb +57 -0
  23. data/lib/aerospike/command/execute_command.rb +42 -0
  24. data/lib/aerospike/command/exists_command.rb +57 -0
  25. data/lib/aerospike/command/field_type.rb +44 -0
  26. data/lib/aerospike/command/operate_command.rb +37 -0
  27. data/lib/aerospike/command/read_command.rb +174 -0
  28. data/lib/aerospike/command/read_header_command.rb +63 -0
  29. data/lib/aerospike/command/single_command.rb +60 -0
  30. data/lib/aerospike/command/touch_command.rb +50 -0
  31. data/lib/aerospike/command/write_command.rb +60 -0
  32. data/lib/aerospike/host.rb +43 -0
  33. data/lib/aerospike/info.rb +96 -0
  34. data/lib/aerospike/key.rb +99 -0
  35. data/lib/aerospike/language.rb +25 -0
  36. data/lib/aerospike/ldt/large.rb +69 -0
  37. data/lib/aerospike/ldt/large_list.rb +100 -0
  38. data/lib/aerospike/ldt/large_map.rb +82 -0
  39. data/lib/aerospike/ldt/large_set.rb +78 -0
  40. data/lib/aerospike/ldt/large_stack.rb +72 -0
  41. data/lib/aerospike/loggable.rb +55 -0
  42. data/lib/aerospike/operation.rb +70 -0
  43. data/lib/aerospike/policy/client_policy.rb +37 -0
  44. data/lib/aerospike/policy/generation_policy.rb +37 -0
  45. data/lib/aerospike/policy/policy.rb +54 -0
  46. data/lib/aerospike/policy/priority.rb +34 -0
  47. data/lib/aerospike/policy/record_exists_action.rb +45 -0
  48. data/lib/aerospike/policy/write_policy.rb +61 -0
  49. data/lib/aerospike/record.rb +42 -0
  50. data/lib/aerospike/result_code.rb +353 -0
  51. data/lib/aerospike/task/index_task.rb +59 -0
  52. data/lib/aerospike/task/task.rb +71 -0
  53. data/lib/aerospike/task/udf_register_task.rb +55 -0
  54. data/lib/aerospike/task/udf_remove_task.rb +55 -0
  55. data/lib/aerospike/udf.rb +24 -0
  56. data/lib/aerospike/utils/buffer.rb +139 -0
  57. data/lib/aerospike/utils/epoc.rb +28 -0
  58. data/lib/aerospike/utils/pool.rb +65 -0
  59. data/lib/aerospike/value/particle_type.rb +45 -0
  60. data/lib/aerospike/value/value.rb +380 -0
  61. data/lib/aerospike/version.rb +4 -0
  62. metadata +132 -0
@@ -0,0 +1,128 @@
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 'base64'
18
+
19
+ module Aerospike
20
+
21
+ private
22
+
23
+ REPLICAS_NAME = 'replicas-master'
24
+
25
+ class PartitionTokenizerNew
26
+
27
+ def initialize(conn)
28
+ # Use low-level info methods and parse byte array directly for maximum performance.
29
+ # Send format: replicas-master\n
30
+ # Receive format: replicas-master\t<ns1>:<base 64 encoded bitmap>;<ns2>:<base 64 encoded bitmap>... \n
31
+ info_map = Info.request(conn, REPLICAS_NAME)
32
+
33
+ info = info_map[REPLICAS_NAME]
34
+
35
+ @length = info ? info.length : 0
36
+
37
+ if !info || @length == 0
38
+ raise Aerospike::Exceptions::Connection.new("#{replicas_name} is empty")
39
+ end
40
+
41
+ @buffer = info
42
+ @offset = 0
43
+
44
+ self
45
+ end
46
+
47
+ def update_partition(nmap, node)
48
+ amap = nil
49
+
50
+ beginning = @offset
51
+ copied = false
52
+
53
+ while @offset < @length
54
+ if @buffer[@offset] == ':'
55
+ # Parse namespace.
56
+ namespace = @buffer[beginning...@offset].strip
57
+
58
+ if namespace.length <= 0 || namespace.length >= 32
59
+ response = get_truncated_response
60
+ raise Aerospike::Exceptions::Parse.new(
61
+ "Invalid partition namespace #{namespace}. Response=#{response}"
62
+ )
63
+ end
64
+
65
+ @offset+=1
66
+ beginning = @offset
67
+
68
+ # Parse partition id.
69
+ while @offset < @length
70
+ b = @buffer[@offset]
71
+
72
+ break if b == ';' || b == "\n"
73
+ @offset+=1
74
+ end
75
+
76
+ if @offset == beginning
77
+ response = get_truncated_response
78
+
79
+ raise Aerospike::Exceptions::Parse.new(
80
+ "Empty partition id for namespace #{namespace}. Response=#{response}"
81
+ )
82
+ end
83
+
84
+ node_array = nmap[namespace]
85
+
86
+ if !node_array
87
+ if !copied
88
+ # Make shallow copy of map.
89
+ amap = {}
90
+ nmap.each {|k, v| amap[k] = Atomic.new(v)}
91
+ copied = true
92
+ end
93
+
94
+ node_array = Atomic.new(Array.new(Aerospike::Node::PARTITIONS))
95
+ amap[namespace] = node_array
96
+ end
97
+
98
+ bit_map_length = @offset - beginning
99
+ restore_buffer = Base64.strict_decode64(@buffer[beginning, bit_map_length])
100
+ for i in 0...Aerospike::Node::PARTITIONS
101
+ if (restore_buffer[i>>3].ord & (0x80 >> (i & 7))) != 0
102
+ # Logger.Info("Map: `" + namespace + "`," + strconv.Itoa(i) + "," + node.String)
103
+ node_array.update{|v| v[i] = node; v}
104
+ end
105
+ end
106
+
107
+ @offset+=1
108
+ beginning = @offset
109
+ else
110
+ @offset+=1
111
+ end
112
+ end
113
+
114
+ copied ? amap : nil
115
+ end
116
+
117
+ private
118
+
119
+ def get_truncated_response
120
+ max = @length
121
+ @length = max if @length > 200
122
+ @buffer[0...max]
123
+ end
124
+
125
+
126
+ end # class
127
+
128
+ end # module
@@ -0,0 +1,135 @@
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 'base64'
18
+
19
+ module Aerospike
20
+
21
+ private
22
+
23
+ class PartitionTokenizerOld
24
+
25
+ def initialize(conn)
26
+ # Use low-level info methods and parse byte array directly for maximum performance.
27
+ # Send format: replicas-master\n
28
+ # Receive format: replicas-master\t<ns1>:<base 64 encoded bitmap>;<ns2>:<base 64 encoded bitmap>... \n
29
+ info_map = Info.request(conn, REPLICAS_NAME)
30
+
31
+ info = info_map[REPLICAS_NAME]
32
+
33
+ @length = info ? info.length : 0
34
+
35
+ if !info || @length == 0
36
+ raise Aerospike::Exceptions::Connection.new("#{replicas_name} is empty")
37
+ end
38
+
39
+ @buffer = info
40
+ @offset = 0
41
+
42
+ self
43
+ end
44
+
45
+ def update_partition(nmap, node)
46
+ amap = nil
47
+ copied = false
48
+
49
+ while partition = get_next
50
+ node_array = nmap[partition.namespace]
51
+
52
+ if !node_array
53
+ if !copied
54
+ # Make shallow copy of map.
55
+ amap = {}
56
+ nmap.each {|k, v| amap[k] = v}
57
+ copied = true
58
+ end
59
+
60
+ node_array = Atomic.new(Array.new(Aerospike::Node::PARTITIONS))
61
+ amap[partition.namespace] = node_array
62
+ end
63
+
64
+ Aerospike.logger.debug("#{partition.to_s}, #{node.name}")
65
+ node_array.update{|v| v[partition.partition_id] = node; v }
66
+ end
67
+
68
+ copied ? amap : nil
69
+ end
70
+
71
+ private
72
+
73
+ def get_next
74
+ beginning = @offset
75
+
76
+ while @offset < @length
77
+ if @buffer[@offset] == ':'
78
+ # Parse namespace.
79
+ namespace = @buffer[beginning...@offset].strip
80
+
81
+ if namespace.length <= 0 || namespace.length >= 32
82
+ response = get_truncated_response
83
+ raise Aerospike::Exceptions::Parse.new(
84
+ "Invalid partition namespace #{namespace}. Response=#{response}"
85
+ )
86
+ end
87
+
88
+ @offset+=1
89
+ beginning = @offset
90
+
91
+ # Parse partition id.
92
+ while @offset < @length
93
+ b = @buffer[@offset]
94
+
95
+ break if b == ';' || b == "\n"
96
+ @offset+=1
97
+ end
98
+
99
+ if @offset == beginning
100
+ response = get_truncated_response
101
+ raise Aerospike::Exceptions::Parse.new(
102
+ "Empty partition id for namespace #{namespace}. Response=#{response}"
103
+ )
104
+ end
105
+
106
+ partition_id = @buffer[beginning...@offset].to_i
107
+ if partition_id < 0 || partition_id >= Aerospike::Node::PARTITIONS
108
+ response = get_truncated_response
109
+ partition_string = @buffer[beginning...@offset]
110
+ raise Aerospike::Exceptions::Parse.new(
111
+ "Invalid partition id #{partition_string} for namespace #{namespace}. Response=#{response}"
112
+ )
113
+ end
114
+
115
+ @offset+=1
116
+ beginning = @offset
117
+
118
+ return Partition.new(namespace, partition_id)
119
+ end
120
+ @offset+=1
121
+ end
122
+ return nil
123
+ end
124
+
125
+
126
+ def get_truncated_response
127
+ max = @length
128
+ @length = max if @length > 200
129
+ @buffer[0...max]
130
+ end
131
+
132
+
133
+ end # class
134
+
135
+ end # module
@@ -0,0 +1,120 @@
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 'thread'
18
+
19
+ require 'aerospike/record'
20
+
21
+ require 'aerospike/command/command'
22
+
23
+ module Aerospike
24
+
25
+ private
26
+
27
+ class BatchCommand < Command
28
+
29
+ def initialize(node)
30
+ super(node)
31
+
32
+ @valid = true
33
+ @mutex = Mutex.new
34
+ @records = Queue.new
35
+
36
+ self
37
+ end
38
+
39
+ def parse_result
40
+ # Read socket into receive buffer one record at a time. Do not read entire receive size
41
+ # because the receive buffer would be too big.
42
+ status = true
43
+
44
+ while status
45
+ # Read header.
46
+ read_bytes(8)
47
+
48
+ size = @data_buffer.read_int64(0)
49
+ receive_size = size & 0xFFFFFFFFFFFF
50
+
51
+ if receive_size > 0
52
+ status = parse_record_results(receive_size)
53
+ else
54
+ status = false
55
+ end
56
+ end
57
+ end
58
+
59
+ def parse_key(field_count)
60
+ digest = nil
61
+ namespace = nil
62
+ set_name = nil
63
+ user_key = nil
64
+
65
+ for i in 0...field_count
66
+ read_bytes(4)
67
+
68
+ fieldlen = @data_buffer.read_int32(0)
69
+ read_bytes(fieldlen)
70
+
71
+ fieldtype = @data_buffer.read(0).ord
72
+ size = fieldlen - 1
73
+
74
+ case fieldtype
75
+ when Aerospike::FieldType::DIGEST_RIPE
76
+ digest = @data_buffer.read(1, size)
77
+ when Aerospike::FieldType::NAMESPACE
78
+ namespace = @data_buffer.read(1, size).force_encoding('utf-8')
79
+ when Aerospike::FieldType::TABLE
80
+ set_name = @data_buffer.read(1, size).force_encoding('utf-8')
81
+ when Aerospike::FieldType::KEY
82
+ user_key = Value.bytes_to_key_value(@data_buffer.read(1).ord, @data_buffer, 2, size-1)
83
+ end
84
+ end
85
+
86
+ Aerospike::Key.new(namespace, set_name, user_key, digest)
87
+ end
88
+
89
+ def read_bytes(length)
90
+ if length > @data_buffer.length
91
+ # Corrupted data streams can result in a huge length.
92
+ # Do a sanity check here.
93
+ if length > Aerospike::Buffer::MAX_BUFFER_SIZE
94
+ raise Aerospike::Exceptions::Parse.new("Invalid read_bytes length: #{length}")
95
+ end
96
+ @data_buffer = Buffer.new(length)
97
+ end
98
+
99
+ @conn.read(@data_buffer, length)
100
+ @data_offset += length
101
+ end
102
+
103
+ def stop
104
+ @mutex.synchronize do
105
+ @valid = false
106
+ end
107
+ end
108
+
109
+ def valid?
110
+ res = nil
111
+ @mutex.synchronize do
112
+ res = @valid
113
+ end
114
+
115
+ res
116
+ end
117
+
118
+ end # class
119
+
120
+ end # module
@@ -0,0 +1,93 @@
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/command/batch_command'
18
+
19
+ module Aerospike
20
+
21
+ private
22
+
23
+ class BatchCommandExists < BatchCommand
24
+
25
+ def initialize(node, batch_namespace, policy, key_map, exists_array)
26
+ super(node)
27
+
28
+ @batch_namespace = batch_namespace
29
+ @policy = policy
30
+ @key_map = key_map
31
+ @exists_array = exists_array
32
+
33
+ self
34
+ end
35
+
36
+ def write_buffer
37
+ set_batch_exists(@batch_namespace)
38
+ end
39
+
40
+ # Parse all results in the batch. Add records to shared list.
41
+ # If the record was not found, the bins will be nil.
42
+ def parse_record_results(receive_size)
43
+ #Parse each message response and add it to the result array
44
+ @data_offset = 0
45
+
46
+ while @data_offset < receive_size
47
+ if !valid?
48
+ raise Aerospike::Exceptions::QueryTerminated.new
49
+ end
50
+
51
+ read_bytes(MSG_REMAINING_HEADER_SIZE)
52
+
53
+ result_code = @data_buffer.read(5).ord & 0xFF
54
+
55
+ # The only valid server return codes are "ok" and "not found".
56
+ # If other return codes are received, then abort the batch.
57
+ if result_code != 0 && result_code != Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
58
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
59
+ end
60
+
61
+ info3 = @data_buffer.read(3).ord
62
+
63
+ # If cmd is the end marker of the response, do not proceed further
64
+ return false if info3 & INFO3_LAST == INFO3_LAST
65
+
66
+ field_count = @data_buffer.read_int16(18)
67
+ op_count = @data_buffer.read_int16(20)
68
+
69
+ if op_count > 0
70
+ raise Aerospike::Exceptions::Parse('Received bins that were not requested!')
71
+ end
72
+
73
+ key = parse_key(field_count)
74
+ item = @key_map[key.digest]
75
+
76
+ if item
77
+ index = item.index
78
+
79
+ # only set the results to true; as a result, no synchronization is needed
80
+ @exists_array[index] = (result_code == 0)
81
+ else
82
+ Aerospike::logger.debug("Unexpected batch key returned: #{key.namespace}, #{key.digest}")
83
+ end
84
+
85
+ end # while
86
+
87
+ return true
88
+ end
89
+
90
+
91
+ end # class
92
+
93
+ end # module