tair 0.1.0.pre
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/Rakefile +6 -0
- data/ext/tair/extconf.rb +3 -0
- data/ext/tair/tair_murmurhash.cpp +72 -0
- data/lib/tair.rb +8 -0
- data/lib/tair/client.rb +107 -0
- data/lib/tair/cluster.rb +51 -0
- data/lib/tair/connection.rb +56 -0
- data/lib/tair/error.rb +6 -0
- data/lib/tair/key.rb +11 -0
- data/lib/tair/log.rb +69 -0
- data/lib/tair/operation/count.rb +12 -0
- data/lib/tair/operation/decr.rb +12 -0
- data/lib/tair/operation/delete.rb +49 -0
- data/lib/tair/operation/fetch_data_servers.rb +123 -0
- data/lib/tair/operation/get.rb +128 -0
- data/lib/tair/operation/incr.rb +76 -0
- data/lib/tair/operation/put.rb +168 -0
- data/lib/tair/protocol.rb +5 -0
- data/lib/tair/protocol/key_meta.rb +9 -0
- data/lib/tair/protocol/murmurhash.rb +11 -0
- data/lib/tair/protocol/response_header.rb +14 -0
- data/lib/tair/protocol/socket_signature.rb +12 -0
- data/lib/tair/protocol/tair_object.rb +67 -0
- data/lib/tair/request.rb +70 -0
- data/lib/tair/response.rb +19 -0
- data/lib/tair/version.rb +12 -0
- data/log/.gitkeep +0 -0
- data/tair.gemspec +34 -0
- metadata +189 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'tair/operation/get'
|
2
|
+
|
3
|
+
module Tair
|
4
|
+
module Operation
|
5
|
+
|
6
|
+
#TODO: support batch delete
|
7
|
+
#FIXME: 某些集群上存在删除失败的bug,需要找时间看一下
|
8
|
+
def delete(key)
|
9
|
+
raise InvalidKeyType unless valid_key?(key)
|
10
|
+
req = DelRequest.new(key)
|
11
|
+
operate(:delete, req, key: key) do |res|
|
12
|
+
DelResponse.new(res).success?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
class DelRequest < GetRequest
|
20
|
+
PACKET_CODE = 3
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class DelResponse < Response
|
25
|
+
|
26
|
+
def success?
|
27
|
+
decode
|
28
|
+
@success
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def decode
|
33
|
+
return if defined? @success
|
34
|
+
Body.read(@body).tap do |body|
|
35
|
+
@success = [0, NON_EXIST_ERR_CODE].include?(body.code)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
NON_EXIST_ERR_CODE = -3998
|
40
|
+
|
41
|
+
|
42
|
+
class Body < BinData::Record
|
43
|
+
int32be :version
|
44
|
+
int32be :code
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
|
3
|
+
module Tair
|
4
|
+
module Operation
|
5
|
+
|
6
|
+
def fetch_data_servers(group)
|
7
|
+
log_time "fetch_data_nodes" do
|
8
|
+
req = FetchDataServerRequest.new(group)
|
9
|
+
config_conn.operate(req) do |res|
|
10
|
+
# TODO: error processing
|
11
|
+
FetchDataServerResponse.new(res).decode
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
class FetchDataServerRequest < Request
|
20
|
+
|
21
|
+
PACKET_CODE = 1002
|
22
|
+
|
23
|
+
attr_accessor :group
|
24
|
+
|
25
|
+
def initialize(group)
|
26
|
+
@group = group
|
27
|
+
end
|
28
|
+
|
29
|
+
def body
|
30
|
+
Body.new(group: group)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
class Body < BinData::Record
|
35
|
+
int32be :version, value: 0
|
36
|
+
int32be :name_len, value: lambda { group.length + 1 }
|
37
|
+
stringz :group
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class FetchDataServerResponse < Response
|
44
|
+
|
45
|
+
def decode
|
46
|
+
Body.read(@body).tap do |body|
|
47
|
+
bucket = body[:bucket]
|
48
|
+
nodes = DataServersInfo.read(Zlib.inflate(body[:ds_data])).nodes.map do |n|
|
49
|
+
[num_str_to_ip(n[:ip_num]), n[:port]].join(":".freeze).freeze
|
50
|
+
end
|
51
|
+
|
52
|
+
Cluster.new.tap do |cluster|
|
53
|
+
cluster.update nodes,
|
54
|
+
nodes_per_bucket: body[:bucket],
|
55
|
+
copying_buckets_count: body[:copy]
|
56
|
+
|
57
|
+
return cluster
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
UNPACK_METHOD = 'C*'.freeze
|
64
|
+
IP_SPLITTER = '.'.freeze
|
65
|
+
|
66
|
+
def num_str_to_ip(str)
|
67
|
+
str.unpack(UNPACK_METHOD).join(IP_SPLITTER).freeze
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
class CString < BinData::Record
|
72
|
+
int32be :len
|
73
|
+
stringz :s_value, read_length: lambda { len }
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
class ConfigServer < BinData::Record
|
78
|
+
c_string :server_name
|
79
|
+
c_string :server_value
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
class DataServer < BinData::Record
|
84
|
+
int32be :port
|
85
|
+
uint8 :ip4
|
86
|
+
uint8 :ip3
|
87
|
+
uint8 :ip2
|
88
|
+
uint8 :ip1
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
class Body < BinData::Record
|
93
|
+
int32be :bucket
|
94
|
+
int32be :copy
|
95
|
+
int32be :version
|
96
|
+
int32be :config_count
|
97
|
+
array :config_servers, type: :config_server, initial_length: lambda { config_count }
|
98
|
+
|
99
|
+
int32be :ds_data_len
|
100
|
+
string :ds_data, read_length: lambda { ds_data_len }
|
101
|
+
|
102
|
+
# 这里的数据现在不关心,所以暂时去掉
|
103
|
+
# TODO: 加上 down_servers 逻辑
|
104
|
+
#int32be :data_server_count
|
105
|
+
#array :data_servers, type: :data_server, initial_length: lambda { data_server_count }
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
# Yet another data server!
|
110
|
+
class YaDataServer < BinData::Record
|
111
|
+
string :ip_num, read_length: 4
|
112
|
+
int32le :port
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
class DataServersInfo < BinData::Record
|
117
|
+
array :nodes, type: :ya_data_server, read_until: :eof
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'tair/key'
|
2
|
+
|
3
|
+
module Tair
|
4
|
+
module Operation
|
5
|
+
|
6
|
+
include ::Tair::Key
|
7
|
+
|
8
|
+
# TODO: support batch get
|
9
|
+
def get(key)
|
10
|
+
raise InvalidKeyType unless valid_key?(key)
|
11
|
+
req = GetRequest.new(key)
|
12
|
+
operate(:get, req, key: key) do |res|
|
13
|
+
GetResponse.new(res).value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :[], :get
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class GetRequest < Request
|
23
|
+
|
24
|
+
PACKET_CODE = 2
|
25
|
+
|
26
|
+
def initialize(key)
|
27
|
+
@key = key
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def body
|
32
|
+
Body.new.tap do |body|
|
33
|
+
body.namespace = namespace || 0
|
34
|
+
body.key = @key
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
class Body < BinData::Record
|
40
|
+
int8 :start_flag, value: 0
|
41
|
+
int16be :namespace
|
42
|
+
int32be :key_count, value: 1
|
43
|
+
array :meta_flag, type: :uint8, initial_length: 7
|
44
|
+
array :default_data, type: :uint8, initial_length: 29
|
45
|
+
tair_object :key_obj
|
46
|
+
|
47
|
+
def key
|
48
|
+
key_obj.value
|
49
|
+
end
|
50
|
+
|
51
|
+
def key=(k)
|
52
|
+
key_obj.value = k
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
class GetResponse < Response
|
60
|
+
|
61
|
+
def value
|
62
|
+
decode
|
63
|
+
@value
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def success?
|
68
|
+
decode
|
69
|
+
@success
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def decode
|
74
|
+
return if defined? @value
|
75
|
+
|
76
|
+
body = Body.read(@body)
|
77
|
+
if @success = body.success?
|
78
|
+
@value = body.succ_data.data.value
|
79
|
+
else
|
80
|
+
# TODO: save failure reason
|
81
|
+
@value = nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
class SuccessData < BinData::Record
|
87
|
+
int8 :merged
|
88
|
+
int32be :area
|
89
|
+
int16be :server_flag
|
90
|
+
int16be :magic
|
91
|
+
int16be :checksum
|
92
|
+
int16be :key_size
|
93
|
+
int16be :meta_version
|
94
|
+
int32be :pad_size
|
95
|
+
int32be :value_size
|
96
|
+
int8 :flag
|
97
|
+
int32be :cdate
|
98
|
+
int32be :mdate
|
99
|
+
int32be :edate
|
100
|
+
|
101
|
+
int32be :data_size #?
|
102
|
+
string :encoded_key, read_length: lambda{ data_size & 0x3FFFFF }
|
103
|
+
key_meta
|
104
|
+
|
105
|
+
tair_object :data
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
class FailureData < BinData::Record
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
class Body < BinData::Record
|
114
|
+
int32be :version
|
115
|
+
uint32be :code
|
116
|
+
int32be :ret_count
|
117
|
+
|
118
|
+
success_data :succ_data, onlyif: :success?
|
119
|
+
|
120
|
+
def success?
|
121
|
+
code == 0
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'tair/operation/get'
|
2
|
+
|
3
|
+
module Tair
|
4
|
+
module Operation
|
5
|
+
|
6
|
+
def incr(key, step=1, op: :incr)
|
7
|
+
valid_key?(key) or fail InvalidKeyType.new(key)
|
8
|
+
valid_count_step?(step) or fail InvalidCountStep.new(step)
|
9
|
+
|
10
|
+
req = IncrRequest.new(key, step)
|
11
|
+
operate(op, req, key: key) do |res|
|
12
|
+
IncrResponse.new(res).count
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def valid_count_step?(step)
|
18
|
+
Fixnum === step
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :increase, :incr
|
22
|
+
alias_method :inc, :incr
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
class IncrRequest < Request
|
29
|
+
|
30
|
+
PACKET_CODE = 11
|
31
|
+
|
32
|
+
def initialize(key, step = 1)
|
33
|
+
@key, @step = key, step
|
34
|
+
end
|
35
|
+
|
36
|
+
def body
|
37
|
+
Body.new.tap do |body|
|
38
|
+
body.step = @step
|
39
|
+
body.key_obj = Tair::TairObject.from(@key)
|
40
|
+
body.namespace = namespace
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Body < BinData::Record
|
45
|
+
int8
|
46
|
+
int16be :namespace
|
47
|
+
int32be :step
|
48
|
+
# 如果不存在时的初始化值,默认为0
|
49
|
+
int32be :init_value
|
50
|
+
int32be :expired_at
|
51
|
+
|
52
|
+
key_meta
|
53
|
+
tair_object :key_obj
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
class IncrResponse < Response
|
60
|
+
|
61
|
+
def count
|
62
|
+
@count ||= decode.current_count.value
|
63
|
+
end
|
64
|
+
|
65
|
+
def decode
|
66
|
+
Body.read(body)
|
67
|
+
end
|
68
|
+
|
69
|
+
class Body < BinData::Record
|
70
|
+
int32be :version
|
71
|
+
int32be :current_count
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Tair
|
2
|
+
module Operation
|
3
|
+
|
4
|
+
include ::Tair::Key
|
5
|
+
include ::Tair::Log
|
6
|
+
|
7
|
+
def put(key, value)
|
8
|
+
raise InvalidKeyType unless valid_key?(key)
|
9
|
+
|
10
|
+
if value.nil?
|
11
|
+
return delete(key)
|
12
|
+
end
|
13
|
+
|
14
|
+
req = PutRequest.new({key => value})
|
15
|
+
|
16
|
+
operate(:put, req, key: key) do |res|
|
17
|
+
PutResponse.new(res).success?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :set, :put
|
22
|
+
alias_method :[]=, :put
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
class PutRequest < Request
|
28
|
+
|
29
|
+
PACKET_CODE = 1
|
30
|
+
|
31
|
+
def initialize(kv)
|
32
|
+
@key, @value = *(kv.to_a.flatten)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def body
|
37
|
+
Body.new.tap do |body|
|
38
|
+
body.key = @key
|
39
|
+
body.value = @value
|
40
|
+
body.namespace = namespace || 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
TAIR_TYPE_STRING = 2
|
45
|
+
|
46
|
+
class Body < BinData::Record
|
47
|
+
int8 :start_flag, value: 0
|
48
|
+
int16be :namespace
|
49
|
+
int16be :data_version
|
50
|
+
int32be :expiring_at
|
51
|
+
key_meta
|
52
|
+
tair_object :key_obj
|
53
|
+
|
54
|
+
key_meta
|
55
|
+
tair_object :value_obj
|
56
|
+
|
57
|
+
|
58
|
+
def key
|
59
|
+
key_obj.value
|
60
|
+
end
|
61
|
+
|
62
|
+
def key=(v)
|
63
|
+
key_obj.value = v
|
64
|
+
end
|
65
|
+
|
66
|
+
def value
|
67
|
+
value_obj.value
|
68
|
+
end
|
69
|
+
|
70
|
+
def value=(v)
|
71
|
+
value_obj.value = v
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
class PutResponse < Response
|
80
|
+
|
81
|
+
def success?
|
82
|
+
return true
|
83
|
+
|
84
|
+
decode
|
85
|
+
@value
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def decode
|
90
|
+
body = Body.read(@body)
|
91
|
+
if body.success?
|
92
|
+
data = body.succ_data
|
93
|
+
type, raw = data.value_type >> 1, data.raw_value
|
94
|
+
@value = case type
|
95
|
+
when TAIR_TYPE_INT then BinData::Double.read(raw).to_i
|
96
|
+
when TAIR_TYPE_STRING then raw.to_s
|
97
|
+
end
|
98
|
+
else
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# tair serialize type
|
105
|
+
TAIR_TYPE_INT = 1
|
106
|
+
TAIR_TYPE_STRING = 2
|
107
|
+
TAIR_TYPE_BOOL = 3
|
108
|
+
TAIR_TYPE_LONG = 4
|
109
|
+
TAIR_TYPE_DATE = 5
|
110
|
+
TAIR_TYPE_BYTE = 6
|
111
|
+
TAIR_TYPE_FLOAT = 7
|
112
|
+
TAIR_TYPE_DOUBLE = 8
|
113
|
+
TAIR_TYPE_BYTEARRAY = 9
|
114
|
+
TAIR_TYPE_SERIALIZE = 10
|
115
|
+
TAIR_TYPE_INCDATA = 11
|
116
|
+
TAIR_TYPE_MIXEDKEY = 12
|
117
|
+
|
118
|
+
|
119
|
+
class SuccessData < BinData::Record
|
120
|
+
int8 :merged
|
121
|
+
int32be :area
|
122
|
+
int16be :server_flag
|
123
|
+
int16be :magic
|
124
|
+
int16be :checksum
|
125
|
+
int16be :key_size
|
126
|
+
int16be :meta_version
|
127
|
+
int32be :pad_size
|
128
|
+
int32be :value_size
|
129
|
+
int8 :flag
|
130
|
+
int32be :cdate
|
131
|
+
int32be :mdate
|
132
|
+
int32be :edate
|
133
|
+
|
134
|
+
int32be :data_size #?
|
135
|
+
string :encoded_key, read_length: lambda{ data_size & 0x3FFFFF }
|
136
|
+
array :key_meta, type: :int8, initial_length: 36
|
137
|
+
int32be :value_len
|
138
|
+
int16be :value_type
|
139
|
+
string :raw_value, read_length: lambda { value_len - 2 }
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
class FailureData < BinData::Record
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
class Body < BinData::Record
|
148
|
+
int32be :version
|
149
|
+
uint32be :code
|
150
|
+
int32be :ret_count
|
151
|
+
|
152
|
+
success_data :succ_data, onlyif: :success?
|
153
|
+
failure_data :fail_data, onlyif: :failed?
|
154
|
+
|
155
|
+
def success?
|
156
|
+
ret_count > 0
|
157
|
+
end
|
158
|
+
|
159
|
+
def failed?
|
160
|
+
!success?
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|