tarantool16 0.0.1
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 +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +2 -0
- data/lib/tarantool16/connection/common.rb +196 -0
- data/lib/tarantool16/connection/dumb.rb +122 -0
- data/lib/tarantool16/connection/response.rb +47 -0
- data/lib/tarantool16/consts.rb +94 -0
- data/lib/tarantool16/db.rb +198 -0
- data/lib/tarantool16/dumb_db.rb +118 -0
- data/lib/tarantool16/errors.rb +82 -0
- data/lib/tarantool16/query.rb +8 -0
- data/lib/tarantool16/response.rb +36 -0
- data/lib/tarantool16/schema.rb +269 -0
- data/lib/tarantool16/version.rb +3 -0
- data/lib/tarantool16.rb +17 -0
- data/tarantool16.gemspec +25 -0
- metadata +104 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'tarantool16/errors'
|
2
|
+
require 'tarantool16/response'
|
3
|
+
|
4
|
+
module Tarantool16
|
5
|
+
module Connection
|
6
|
+
class Option
|
7
|
+
attr :sync, :error, :data
|
8
|
+
def initialize(sync, err, data)
|
9
|
+
@sync = sync
|
10
|
+
@error = err
|
11
|
+
@data = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def ok?
|
15
|
+
!@error
|
16
|
+
end
|
17
|
+
|
18
|
+
def raise_if_error!
|
19
|
+
raise @error if @error
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.ok(sync, code, data)
|
23
|
+
if code == 0
|
24
|
+
new(sync, nil, data)
|
25
|
+
else
|
26
|
+
new(sync, ::Tarantool16::DBError.with_code_message(code, data), nil)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.error(sync, err, message = nil)
|
31
|
+
if err.is_a? Class
|
32
|
+
err = err.new message
|
33
|
+
end
|
34
|
+
new(sync, err, nil)
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
s = @sync ? " sync=#{sync}" : ""
|
39
|
+
if ok?
|
40
|
+
"<Option#{s} data=#{@data.inspect}>"
|
41
|
+
else
|
42
|
+
"<Option#{s} error=#{@error.inspect}>"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Tarantool16
|
2
|
+
IPROTO_CODE = 0x00
|
3
|
+
IPROTO_SYNC = 0x01
|
4
|
+
IPROTO_SPACE_ID = 0x10
|
5
|
+
IPROTO_INDEX_ID = 0x11
|
6
|
+
IPROTO_LIMIT = 0x12
|
7
|
+
IPROTO_OFFSET = 0x13
|
8
|
+
IPROTO_ITERATOR = 0x14
|
9
|
+
IPROTO_KEY = 0x20
|
10
|
+
IPROTO_TUPLE = 0x21
|
11
|
+
IPROTO_FUNCTION_NAME = 0x22
|
12
|
+
IPROTO_USER_NAME = 0x23
|
13
|
+
IPROTO_DATA = 0x30
|
14
|
+
IPROTO_ERROR = 0x31
|
15
|
+
|
16
|
+
IPROTO_GREETING_SIZE = 128
|
17
|
+
|
18
|
+
REQUEST_TYPE_OK = 0
|
19
|
+
REQUEST_TYPE_PING = 64
|
20
|
+
REQUEST_TYPE_SELECT = 1
|
21
|
+
REQUEST_TYPE_INSERT = 2
|
22
|
+
REQUEST_TYPE_REPLACE = 3
|
23
|
+
REQUEST_TYPE_UPDATE = 4
|
24
|
+
REQUEST_TYPE_DELETE = 5
|
25
|
+
REQUEST_TYPE_CALL = 6
|
26
|
+
REQUEST_TYPE_AUTHENTICATE = 7
|
27
|
+
REQUEST_TYPE_ERROR = 1 << 15
|
28
|
+
|
29
|
+
|
30
|
+
SPACE_SCHEMA = 272
|
31
|
+
SPACE_SPACE = 280
|
32
|
+
SPACE_INDEX = 288
|
33
|
+
SPACE_FUNC = 296
|
34
|
+
SPACE_USER = 304
|
35
|
+
SPACE_PRIV = 312
|
36
|
+
SPACE_CLUSTER = 320
|
37
|
+
|
38
|
+
INDEX_SPACE_PRIMARY = 0
|
39
|
+
INDEX_SPACE_NAME = 2
|
40
|
+
INDEX_INDEX_PRIMARY = 0
|
41
|
+
INDEX_INDEX_NAME = 2
|
42
|
+
|
43
|
+
ITERATOR_EQ = 0
|
44
|
+
ITERATOR_REQ = 1
|
45
|
+
ITERATOR_ALL = 2
|
46
|
+
ITERATOR_LT = 3
|
47
|
+
ITERATOR_LE = 4
|
48
|
+
ITERATOR_GE = 5
|
49
|
+
ITERATOR_GT = 6
|
50
|
+
ITERATOR_BITS_ALL_SET = 7
|
51
|
+
ITERATOR_BITS_ANY_SET = 8
|
52
|
+
ITERATOR_BITS_ALL_NOT_SET = 9
|
53
|
+
ITERATOR_RTREE_OVERLAPS = 10
|
54
|
+
ITERATOR_RTREE_NEIGHBOR = 11
|
55
|
+
|
56
|
+
Iterators = {}
|
57
|
+
[
|
58
|
+
[ITERATOR_EQ, %w[eq ==]],
|
59
|
+
[ITERATOR_REQ, %w[req rev ==<]],
|
60
|
+
[ITERATOR_ALL, %w[all *]],
|
61
|
+
[ITERATOR_LT, %w[< lt]],
|
62
|
+
[ITERATOR_LE, %w[<= le]],
|
63
|
+
[ITERATOR_GE, %w[>= ge]],
|
64
|
+
[ITERATOR_GT, %w[> gt]],
|
65
|
+
[ITERATOR_BITS_ALL_SET, %w[ball &=]],
|
66
|
+
[ITERATOR_BITS_ANY_SET, %w[bany &]],
|
67
|
+
[ITERATOR_BITS_ALL_NOT_SET, %w[bnotany !&]],
|
68
|
+
[ITERATOR_RTREE_OVERLAPS, %w[roverlaps here &&]],
|
69
|
+
[ITERATOR_RTREE_NEIGHBOR, %w[rneighbor near <->]],
|
70
|
+
].each do |it, names|
|
71
|
+
names.each do |name|
|
72
|
+
Iterators[it] = it
|
73
|
+
Iterators[name] = it
|
74
|
+
Iterators[name.to_sym] = it
|
75
|
+
end
|
76
|
+
end
|
77
|
+
Iterators[nil] = ITERATOR_EQ
|
78
|
+
def self.iter(iter)
|
79
|
+
unless it = Iterators[iter]
|
80
|
+
raise "Unknown iterator #{iter.inspect}"
|
81
|
+
end
|
82
|
+
it
|
83
|
+
end
|
84
|
+
|
85
|
+
# Default value for socket timeout (seconds)
|
86
|
+
SOCKET_TIMEOUT = nil
|
87
|
+
# Default maximum number of attempts to reconnect
|
88
|
+
RECONNECT_MAX_ATTEMPTS = 10
|
89
|
+
# Default delay between attempts to reconnect (seconds)
|
90
|
+
RECONNECT_DELAY = 0.1
|
91
|
+
# Number of reattempts in case of server
|
92
|
+
# return completion_status == 1 (try again)
|
93
|
+
RETRY_MAX_ATTEMPTS = 10
|
94
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require_relative 'schema'
|
2
|
+
module Tarantool16
|
3
|
+
class DB
|
4
|
+
attr :conn
|
5
|
+
|
6
|
+
def initialize(host, opts = {})
|
7
|
+
@host = host
|
8
|
+
@opts = opts.dup
|
9
|
+
@future = nil
|
10
|
+
@spaces = nil
|
11
|
+
@defined_fields = {}
|
12
|
+
_fill_standard_spaces
|
13
|
+
@conn = self.class::Connection.new(@host, @opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def define_fields(sid, fields)
|
17
|
+
sid = sid.to_s if sid.is_a?(Symbol)
|
18
|
+
@defined_fields[sid] = fields
|
19
|
+
if @spaces && (sp = @spaces[sid])
|
20
|
+
if sp.sid && sp.name && !sp.name.empty?
|
21
|
+
rf1 = @defined_fields[sp.sid]
|
22
|
+
rf2 = @defined_fields[sp.name]
|
23
|
+
if rf1 && rf2 && rf1 != rf2
|
24
|
+
raise "Misconfigured defined fields for #{sp.name_sid}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
sp.fields = fields
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def _fill_standard_spaces
|
32
|
+
rf = @defined_fields
|
33
|
+
rf[SPACE_INDEX] =
|
34
|
+
[%w{sid num}, %w{iid num}, %w{name str},
|
35
|
+
%w{type str}, %w{unique num}, %w{part_count num},
|
36
|
+
{name: 'parts', type: [:num, :str], tail: true}]
|
37
|
+
end
|
38
|
+
|
39
|
+
def _synchronized
|
40
|
+
raise "Override #_synchronized"
|
41
|
+
end
|
42
|
+
|
43
|
+
UNDEF = Object.new.freeze
|
44
|
+
def _with_space(name, cb)
|
45
|
+
future = @future || _space_future
|
46
|
+
future.then_blk do |r|
|
47
|
+
unless r.ok?
|
48
|
+
cb.call r
|
49
|
+
else
|
50
|
+
sps = r.data
|
51
|
+
sp = sps[name]
|
52
|
+
if sp.nil? && Symbol == name
|
53
|
+
sp = sps[name.to_s]
|
54
|
+
sps[name] = sp unless sp.nil?
|
55
|
+
end
|
56
|
+
if sp.nil?
|
57
|
+
cb.call Option.error(SchemaError, "space #{name} not found")
|
58
|
+
else
|
59
|
+
yield sp
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def _space_future
|
66
|
+
_synchronized do
|
67
|
+
return @future if @future
|
68
|
+
future = @future = self.class::SchemaFuture.new
|
69
|
+
fill_indexes = nil
|
70
|
+
spaces = nil
|
71
|
+
fill_spaces = lambda do|r|
|
72
|
+
unless r.ok?
|
73
|
+
future.set r
|
74
|
+
_synchronized do
|
75
|
+
@future = nil
|
76
|
+
end
|
77
|
+
else
|
78
|
+
_synchronized do
|
79
|
+
_fill_spaces(r.data)
|
80
|
+
spaces = @spaces
|
81
|
+
_select(SPACE_INDEX, 0, [], 0, 2**30, :all, false, fill_indexes)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
fill_indexes = lambda do |r|
|
86
|
+
unless r.ok?
|
87
|
+
future.set r
|
88
|
+
_synchronized do
|
89
|
+
@future = nil
|
90
|
+
@spaces = nil
|
91
|
+
end
|
92
|
+
else
|
93
|
+
_synchronized do
|
94
|
+
_fill_indices(spaces, r.data)
|
95
|
+
future.set Option.ok(spaces)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
_select(SPACE_SPACE, 0, [], 0, 2**30, :all, false, fill_spaces)
|
100
|
+
return future
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def _fill_spaces(rows)
|
105
|
+
@spaces = {}
|
106
|
+
rows.each do |row|
|
107
|
+
fields = @defined_fields[row[0]] || @defined_fields[row[2]] || row[6]
|
108
|
+
sp = SchemaSpace.new(row[0], row[2], fields)
|
109
|
+
@spaces[row[0]] = sp
|
110
|
+
@spaces[sp.name] = sp
|
111
|
+
@spaces[sp.name.to_sym] = sp
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def _fill_indices(spaces, rows)
|
116
|
+
rows.
|
117
|
+
map{|row| [row[0], [row[2], row[1], row[3], 6.step(row.size-1, 2).map{|i| row[i]}]]}.
|
118
|
+
group_by{|sid, _| sid}.
|
119
|
+
each do |sid, inds|
|
120
|
+
sp = spaces[sid]
|
121
|
+
sp.indices = inds.map{|_sid, ind| ind}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def _insert(sno, tuple, need_hash, cb)
|
126
|
+
if !need_hash && sno.is_a?(Integer) && tuple.is_a?(Array)
|
127
|
+
return conn._insert(sno, tuple, cb)
|
128
|
+
end
|
129
|
+
_with_space(sno, cb) do |sp|
|
130
|
+
_tuple = tuple.is_a?(Hash) ? sp.map_tuple(tuple) : tuple
|
131
|
+
_cb = need_hash ? sp.wrap_cb(cb) : cb
|
132
|
+
conn._insert(sp.sid, _tuple, _cb)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def _replace(sno, tuple, need_hash, cb)
|
137
|
+
if !need_hash && sno.is_a?(Integer) && tuple.is_a?(Array)
|
138
|
+
return conn._replace(sno, tuple, cb)
|
139
|
+
end
|
140
|
+
_with_space(sno, cb) do |sp|
|
141
|
+
_tuple = tuple.is_a?(Hash) ? sp.map_tuple(tuple) : tuple
|
142
|
+
_cb = need_hash ? sp.wrap_cb(cb) : cb
|
143
|
+
conn.insert(sp.sid, _tuple, _cb)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def _delete(sno, ino, key, need_hash, cb)
|
148
|
+
ino = 0 if ino.nil? && key.is_a?(Array)
|
149
|
+
if !need_hash && sno.is_a?(Integer) && ino.is_a?(Integer) && key.is_a?(Array)
|
150
|
+
return conn._delete(sno, ino, key, cb)
|
151
|
+
end
|
152
|
+
_with_space(sno, cb) do |sp|
|
153
|
+
sp.get_ino(ino, key, ITERATOR_EQ, cb) do |_ino, _key|
|
154
|
+
_cb = need_hash ? sp.wrap_cb(cb) : cb
|
155
|
+
conn._delete(sp.sid, _ino, _key, _cb)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def _select(sno, ino, key, offset, limit, iterator, need_hash, cb)
|
161
|
+
key = [] if key.nil?
|
162
|
+
ino = 0 if ino.nil? && key.is_a?(Array)
|
163
|
+
iterator = ::Tarantool16.iter(iterator) unless iterator.is_a?(Integer)
|
164
|
+
if sno.is_a?(Integer) && ino.is_a?(Integer) && (key.is_a?(Array) || key.nil?)
|
165
|
+
return conn._select(sno, ino, key, offset, limit, iterator, cb)
|
166
|
+
end
|
167
|
+
_with_space(sno, cb) do |sp|
|
168
|
+
sp.get_ino(ino, key, iterator, cb) do |_ino, _key|
|
169
|
+
_cb = need_hash ? sp.wrap_cb(cb) : cb
|
170
|
+
conn._select(sp.sid, _ino, _key, offset, limit, iterator, _cb)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def _update(sno, ino, key, ops, need_hash, cb)
|
176
|
+
ino = 0 if ino.nil? && key.is_a?(Array)
|
177
|
+
ops_good = ops.is_a?(Array) && ops.all?{|a| ops[1].is_a?(Integer)}
|
178
|
+
if sno.is_a?(Integer) && ino.is_a?(Integer) && key.is_a?(Array) && ops_good
|
179
|
+
return conn._update(sno, ino, key, ops, cb)
|
180
|
+
end
|
181
|
+
_with_space(sno, cb) do |sp|
|
182
|
+
sp.get_ino(ino, key, ITERATOR_EQ, cb) do |_ino, _key|
|
183
|
+
_ops = ops_good ? ops : sp.map_ops(ops)
|
184
|
+
_cb = need_hash ? sp.wrap_cb(cb) : cb
|
185
|
+
conn._update(sp.sid, _ino, _key, _ops, _cb)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def _call(name, args, cb)
|
191
|
+
conn._call(name, args, cb)
|
192
|
+
end
|
193
|
+
|
194
|
+
def _ping(cb)
|
195
|
+
conn._ping(cb)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative 'db'
|
2
|
+
require_relative 'connection/dumb'
|
3
|
+
|
4
|
+
module Tarantool16
|
5
|
+
class DumbDB < DB
|
6
|
+
Connection = Tarantool16::Connection::Dumb
|
7
|
+
|
8
|
+
RETURN_OR_RAISE = lambda{|r|
|
9
|
+
raise r.error unless r.ok?
|
10
|
+
r.data
|
11
|
+
}
|
12
|
+
RETURN_ONE_OR_RAISE = lambda{|r|
|
13
|
+
raise r.error unless r.ok?
|
14
|
+
r.data[0]
|
15
|
+
}
|
16
|
+
HUGE_LIMIT = 2**30
|
17
|
+
|
18
|
+
def select(sno, key, opts={})
|
19
|
+
ino = opts[:index]
|
20
|
+
offset = opts[:offset] || 0
|
21
|
+
limit = opts[:limit] || 2**30
|
22
|
+
iterator = opts[:iterator]
|
23
|
+
need_hash = opts[:hash]
|
24
|
+
key = case key
|
25
|
+
when nil
|
26
|
+
[]
|
27
|
+
when Array
|
28
|
+
key
|
29
|
+
when Hash
|
30
|
+
need_hash = true
|
31
|
+
key
|
32
|
+
else
|
33
|
+
[key]
|
34
|
+
end
|
35
|
+
_select(sno, ino, key, offset, limit, iterator, need_hash, RETURN_OR_RAISE)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get(sno, key, opts={})
|
39
|
+
ino = opts[:index]
|
40
|
+
iterator = opts[:iterator]
|
41
|
+
need_hash = opts[:hash]
|
42
|
+
key = case key
|
43
|
+
when nil
|
44
|
+
[]
|
45
|
+
when Array
|
46
|
+
key
|
47
|
+
when Hash
|
48
|
+
need_hash = true
|
49
|
+
key
|
50
|
+
else
|
51
|
+
[key]
|
52
|
+
end
|
53
|
+
_select(sno, ino, key, 0, 1, iterator, need_hash, RETURN_ONE_OR_RAISE)
|
54
|
+
end
|
55
|
+
|
56
|
+
def insert(sno, tuple, opts = {})
|
57
|
+
need_hash = opts[:hash] || tuple.is_a?(Hash)
|
58
|
+
_insert(sno, tuple, need_hash, RETURN_OR_RAISE)
|
59
|
+
end
|
60
|
+
|
61
|
+
def replace(sno, tuple, opts = {})
|
62
|
+
need_hash = opts[:hash] || tuple.is_a?(Hash)
|
63
|
+
_replace(sno, tuple, need_hash, RETURN_OR_RAISE)
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete(sno, key, opts = {})
|
67
|
+
ino = opts[:index]
|
68
|
+
need_hash = opts[:hash] || tkey.is_a?(Hash)
|
69
|
+
_delete(sno, ino, key, need_hash, RETURN_OR_RAISE)
|
70
|
+
end
|
71
|
+
|
72
|
+
def update(sno, key, ops, opts = {})
|
73
|
+
ino = opts[:index]
|
74
|
+
need_hash = opts[:hash] || key.is_a?(Hash)
|
75
|
+
_update(sno, ino, key, ops, need_hash, RETURN_OR_RAISE)
|
76
|
+
end
|
77
|
+
|
78
|
+
def _synchronized
|
79
|
+
yield
|
80
|
+
end
|
81
|
+
|
82
|
+
class SchemaFuture
|
83
|
+
UNDEF = Object.new.freeze
|
84
|
+
def initialize
|
85
|
+
@r = UNDEF
|
86
|
+
@cb = nil
|
87
|
+
end
|
88
|
+
def then(cb)
|
89
|
+
unless @r.equal? UNDEF
|
90
|
+
return cb.call(@r)
|
91
|
+
end
|
92
|
+
if @cb
|
93
|
+
raise "Blocking future accepts only 1 callback"
|
94
|
+
end
|
95
|
+
@cb = cb
|
96
|
+
end
|
97
|
+
|
98
|
+
def then_blk
|
99
|
+
unless @r.equal? UNDEF
|
100
|
+
return yield @r
|
101
|
+
end
|
102
|
+
if @cb
|
103
|
+
raise "Blocking future accepts only 1 callback"
|
104
|
+
end
|
105
|
+
@cb = lambda{|r| yield r}
|
106
|
+
end
|
107
|
+
|
108
|
+
def set(r)
|
109
|
+
@r = r
|
110
|
+
if cb = @cb
|
111
|
+
@cb = nil
|
112
|
+
cb.call(r)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|