tair 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|