tarantool-client 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/README.md +79 -1
- data/lib/tarantool/client/batch_delete.rb +97 -0
- data/lib/tarantool/client/configuration.rb +20 -3
- data/lib/tarantool/client/diagnostics.rb +20 -0
- data/lib/tarantool/client/errors.rb +8 -1
- data/lib/tarantool/client/fork_safety.rb +2 -1
- data/lib/tarantool/client/instrumentation/log_instrumenter.rb +35 -0
- data/lib/tarantool/client/instrumentation/log_lines.rb +66 -0
- data/lib/tarantool/client/instrumentation/request_payload.rb +42 -0
- data/lib/tarantool/client/instrumentation.rb +51 -0
- data/lib/tarantool/client/instrumented.rb +42 -0
- data/lib/tarantool/client/named_requests.rb +67 -0
- data/lib/tarantool/client/operations.rb +53 -21
- data/lib/tarantool/client/pool/member.rb +4 -9
- data/lib/tarantool/client/pool/member_fork_safety.rb +10 -5
- data/lib/tarantool/client/pool/member_role.rb +36 -0
- data/lib/tarantool/client/row.rb +8 -0
- data/lib/tarantool/client/schema.rb +4 -3
- data/lib/tarantool/client/space_info.rb +2 -0
- data/lib/tarantool/client/stream.rb +20 -10
- data/lib/tarantool/client/transaction_schema.rb +12 -8
- data/lib/tarantool/client/transport/connection.rb +2 -0
- data/lib/tarantool/client/transport/link.rb +15 -15
- data/lib/tarantool/client/transport/link_events.rb +41 -0
- data/lib/tarantool/client/transport/link_state.rb +10 -0
- data/lib/tarantool/client/tuple_mapping.rb +65 -0
- data/lib/tarantool/client/tuple_shape.rb +25 -0
- data/lib/tarantool/client/version.rb +1 -1
- data/lib/tarantool/client.rb +23 -48
- metadata +15 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tarantool
|
|
4
|
+
class Client
|
|
5
|
+
# Tuple <-> Hash by the space format, for SpaceInfo. Fields beyond the format are keyed by their 0-based position.
|
|
6
|
+
# @api private
|
|
7
|
+
module TupleMapping
|
|
8
|
+
# A position this far past the format would otherwise let a huge Integer key allocate a giant Array.
|
|
9
|
+
MAX_POSITIONS_BEYOND_FORMAT = 1024
|
|
10
|
+
|
|
11
|
+
def to_hash(tuple)
|
|
12
|
+
hash = fields.each_with_index.to_h { |field, position| [field.name.to_sym, tuple[position]] }
|
|
13
|
+
(fields.size...tuple.size).each { |position| hash[position] = tuple[position] }
|
|
14
|
+
|
|
15
|
+
hash
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# A missing field goes out as nil; on 3.x the server applies the field default to nil as well.
|
|
19
|
+
def to_tuple(hash)
|
|
20
|
+
positions = fields.each_with_index.to_h { |field, position| [field.name, position] }
|
|
21
|
+
named_positions = {}
|
|
22
|
+
|
|
23
|
+
hash.each_with_object(Array.new(fields.size)) do |(key, value), tuple|
|
|
24
|
+
position = position_of(key, positions)
|
|
25
|
+
check_not_duplicate(key, position, named_positions)
|
|
26
|
+
tuple[position] = value
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def position_of(key, positions)
|
|
33
|
+
case key
|
|
34
|
+
when Symbol, String
|
|
35
|
+
positions.fetch(key.to_s) { raise UnknownFieldError, "space #{name} has no field '#{key}'" }
|
|
36
|
+
when Integer then position_beyond_format(key)
|
|
37
|
+
else raise ArgumentError, "unsupported key #{key.inspect} for space #{name}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# `:a` and 'a' name the same field; the later one would otherwise win silently.
|
|
42
|
+
def check_not_duplicate(key, position, named_positions)
|
|
43
|
+
return unless key.is_a?(Symbol) || key.is_a?(String)
|
|
44
|
+
raise ArgumentError, "space #{name} field '#{fields[position].name}' given twice" if named_positions[position]
|
|
45
|
+
|
|
46
|
+
named_positions[position] = true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def position_beyond_format(position)
|
|
50
|
+
raise ArgumentError, "position #{position} is negative for space #{name}" if position.negative?
|
|
51
|
+
|
|
52
|
+
if position < fields.size
|
|
53
|
+
raise ArgumentError, "position #{position} is inside the format of space #{name}; use the field name"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if position >= fields.size + MAX_POSITIONS_BEYOND_FORMAT
|
|
57
|
+
raise ArgumentError, "position #{position} is more than #{MAX_POSITIONS_BEYOND_FORMAT} past the format " \
|
|
58
|
+
"of space #{name}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
position
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tarantool
|
|
4
|
+
class Client
|
|
5
|
+
# What data operations return for each tuple, chosen with `as:`.
|
|
6
|
+
# @api private
|
|
7
|
+
module TupleShape
|
|
8
|
+
SHAPES = %i[tuple hash row].freeze
|
|
9
|
+
|
|
10
|
+
def self.check(shape)
|
|
11
|
+
return if SHAPES.include?(shape)
|
|
12
|
+
|
|
13
|
+
raise ArgumentError, "unknown as: #{shape.inspect}, expected one of #{SHAPES.join(', ')}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.apply(shape, tuple, space_info)
|
|
17
|
+
case shape
|
|
18
|
+
when :hash then space_info.to_hash(tuple)
|
|
19
|
+
when :row then Row.new(tuple:, attributes: space_info.to_hash(tuple))
|
|
20
|
+
else tuple
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/tarantool/client.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative 'client/errors'
|
|
|
8
8
|
require_relative 'client/configuration'
|
|
9
9
|
require_relative 'client/backoff'
|
|
10
10
|
require_relative 'client/thread_join'
|
|
11
|
+
require_relative 'client/diagnostics'
|
|
11
12
|
require_relative 'client/protocol/constants'
|
|
12
13
|
require_relative 'client/box_error'
|
|
13
14
|
require_relative 'client/uuid'
|
|
@@ -40,6 +41,12 @@ require_relative 'client/protocol/requests/auth'
|
|
|
40
41
|
require_relative 'client/protocol/requests/id'
|
|
41
42
|
require_relative 'client/protocol/requests/watch'
|
|
42
43
|
require_relative 'client/protocol/requests/unwatch'
|
|
44
|
+
require_relative 'client/instrumentation'
|
|
45
|
+
require_relative 'client/instrumentation/request_payload'
|
|
46
|
+
require_relative 'client/instrumentation/log_lines'
|
|
47
|
+
require_relative 'client/instrumentation/log_instrumenter'
|
|
48
|
+
require_relative 'client/instrumented'
|
|
49
|
+
require_relative 'client/named_requests'
|
|
43
50
|
require_relative 'client/transport/future'
|
|
44
51
|
require_relative 'client/transport/pending_requests'
|
|
45
52
|
require_relative 'client/transport/stream_ids'
|
|
@@ -50,14 +57,19 @@ require_relative 'client/transport/frame_writer'
|
|
|
50
57
|
require_relative 'client/transport/handshake'
|
|
51
58
|
require_relative 'client/transport/connection'
|
|
52
59
|
require_relative 'client/transport/link_state'
|
|
60
|
+
require_relative 'client/transport/link_events'
|
|
53
61
|
require_relative 'client/transport/link'
|
|
54
62
|
require_relative 'client/index_info'
|
|
63
|
+
require_relative 'client/tuple_mapping'
|
|
55
64
|
require_relative 'client/space_info'
|
|
56
65
|
require_relative 'client/schema'
|
|
57
66
|
require_relative 'client/schema_cache'
|
|
58
67
|
require_relative 'client/sql_result'
|
|
59
68
|
require_relative 'client/prepared_statement'
|
|
69
|
+
require_relative 'client/batch_delete'
|
|
60
70
|
require_relative 'client/transaction_schema'
|
|
71
|
+
require_relative 'client/row'
|
|
72
|
+
require_relative 'client/tuple_shape'
|
|
61
73
|
require_relative 'client/operations'
|
|
62
74
|
require_relative 'client/transaction_scope'
|
|
63
75
|
require_relative 'client/stream'
|
|
@@ -68,6 +80,7 @@ require_relative 'client/watchers/dispatcher'
|
|
|
68
80
|
require_relative 'client/fork_safety'
|
|
69
81
|
require_relative 'client/pool'
|
|
70
82
|
require_relative 'client/pool/member_fork_safety'
|
|
83
|
+
require_relative 'client/pool/member_role'
|
|
71
84
|
require_relative 'client/pool/member'
|
|
72
85
|
|
|
73
86
|
module Tarantool
|
|
@@ -75,6 +88,8 @@ module Tarantool
|
|
|
75
88
|
class Client
|
|
76
89
|
include Operations
|
|
77
90
|
include ForkSafety
|
|
91
|
+
include Instrumented
|
|
92
|
+
include NamedRequests
|
|
78
93
|
|
|
79
94
|
attr_reader :config
|
|
80
95
|
|
|
@@ -85,6 +100,7 @@ module Tarantool
|
|
|
85
100
|
|
|
86
101
|
def initialize(uri = nil, **)
|
|
87
102
|
@config = Configuration.build(uri, **)
|
|
103
|
+
@instrumentation = Instrumentation.build(@config)
|
|
88
104
|
@pid = Process.pid
|
|
89
105
|
@reinit_lock = Mutex.new
|
|
90
106
|
open_link
|
|
@@ -107,7 +123,7 @@ module Tarantool
|
|
|
107
123
|
TransactionScope.enter(self) do
|
|
108
124
|
stream = Stream.new(
|
|
109
125
|
connection: @link.connection, schema_cache: @schema_cache, id: @stream_ids.next,
|
|
110
|
-
request_timeout: @config.request_timeout
|
|
126
|
+
request_timeout: @config.request_timeout, instrumentation: @instrumentation
|
|
111
127
|
)
|
|
112
128
|
stream.transaction(isolation:, timeout:, &block)
|
|
113
129
|
end
|
|
@@ -139,7 +155,7 @@ module Tarantool
|
|
|
139
155
|
|
|
140
156
|
def link_hooks = { on_connect: method(:load_schema), on_ready: method(:resubscribe), on_lost: method(:lost) }
|
|
141
157
|
|
|
142
|
-
def
|
|
158
|
+
def transmit(request, timeout: nil, schema_version: nil, on_push: nil)
|
|
143
159
|
ensure_fork_safe
|
|
144
160
|
@link.perform(request, timeout: timeout || @config.request_timeout, schema_version:, on_push:)
|
|
145
161
|
end
|
|
@@ -164,53 +180,12 @@ module Tarantool
|
|
|
164
180
|
|
|
165
181
|
# Name-resolved requests carry the schema version they were resolved against, so the
|
|
166
182
|
# server rejects them (ER_WRONG_SCHEMA_VERSION) instead of running them on a stale id.
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
# A request that needs the space format is resolved the same way even by ids, so the
|
|
184
|
+
# format and the version it carries come from one schema.
|
|
185
|
+
def transmit_on_space(space, index, timeout: nil, format: false, payload: nil, &)
|
|
186
|
+
return transmit(yield(space, index), timeout:) if !format && space.is_a?(Integer) && index.is_a?(Integer)
|
|
169
187
|
|
|
170
|
-
perform_by_name(space, index, timeout || @config.request_timeout, &)
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# Every schema fetch and attempt draws on one deadline, so the whole call stays within timeout.
|
|
174
|
-
# Waiting for a connection first means the cache already holds its schema or a newer one.
|
|
175
|
-
def perform_by_name(space, index, timeout, &)
|
|
176
|
-
ensure_fork_safe
|
|
177
|
-
deadline = Transport::Deadline.after(timeout)
|
|
178
|
-
@link.connection(deadline)
|
|
179
|
-
|
|
180
|
-
perform_with_schema_check(space, index, deadline, &)
|
|
181
|
-
rescue TimeoutError
|
|
182
|
-
raise TimeoutError, "no response within #{timeout}s"
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def lookup_space(space, timeout)
|
|
186
|
-
ensure_fork_safe
|
|
187
|
-
timeout ||= @config.request_timeout
|
|
188
|
-
deadline = Transport::Deadline.after(timeout)
|
|
189
|
-
@link.connection(deadline)
|
|
190
|
-
|
|
191
|
-
@schema_cache.space_info(space, deadline)
|
|
192
|
-
rescue TimeoutError
|
|
193
|
-
raise TimeoutError, "no response within #{timeout}s"
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def perform_with_schema_check(space, index, deadline)
|
|
197
|
-
schema, ids = @schema_cache.resolve(space, index, deadline)
|
|
198
|
-
|
|
199
|
-
perform_resolved(schema, yield(*ids), deadline)
|
|
200
|
-
rescue ServerError => e
|
|
201
|
-
raise unless e.code == Protocol::Constants::ER_WRONG_SCHEMA_VERSION
|
|
202
|
-
|
|
203
|
-
fresh = @schema_cache.reload(schema, timeout: Transport::Deadline.remaining(deadline))
|
|
204
|
-
schema, ids = @schema_cache.resolve(space, index, deadline, fresh)
|
|
205
|
-
perform_resolved(schema, yield(*ids), deadline)
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
# Only the connection the schema came from: once it is lost, another instance may reuse the
|
|
209
|
-
# schema version with other ids, so the request fails with it rather than wait for a reconnect.
|
|
210
|
-
def perform_resolved(schema, request, deadline)
|
|
211
|
-
timeout = Transport::Deadline.remaining(deadline)
|
|
212
|
-
|
|
213
|
-
schema.connection.perform(request, timeout:, schema_version: schema.version)
|
|
188
|
+
perform_by_name(space, index, timeout || @config.request_timeout, payload, &)
|
|
214
189
|
end
|
|
215
190
|
end
|
|
216
191
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tarantool-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Starlexxx
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigdecimal
|
|
@@ -52,17 +52,26 @@ files:
|
|
|
52
52
|
- README.md
|
|
53
53
|
- lib/tarantool/client.rb
|
|
54
54
|
- lib/tarantool/client/backoff.rb
|
|
55
|
+
- lib/tarantool/client/batch_delete.rb
|
|
55
56
|
- lib/tarantool/client/box_error.rb
|
|
56
57
|
- lib/tarantool/client/callback_guard.rb
|
|
57
58
|
- lib/tarantool/client/configuration.rb
|
|
59
|
+
- lib/tarantool/client/diagnostics.rb
|
|
58
60
|
- lib/tarantool/client/errors.rb
|
|
59
61
|
- lib/tarantool/client/fork_safety.rb
|
|
60
62
|
- lib/tarantool/client/index_info.rb
|
|
63
|
+
- lib/tarantool/client/instrumentation.rb
|
|
64
|
+
- lib/tarantool/client/instrumentation/log_instrumenter.rb
|
|
65
|
+
- lib/tarantool/client/instrumentation/log_lines.rb
|
|
66
|
+
- lib/tarantool/client/instrumentation/request_payload.rb
|
|
67
|
+
- lib/tarantool/client/instrumented.rb
|
|
61
68
|
- lib/tarantool/client/interval.rb
|
|
69
|
+
- lib/tarantool/client/named_requests.rb
|
|
62
70
|
- lib/tarantool/client/operations.rb
|
|
63
71
|
- lib/tarantool/client/pool.rb
|
|
64
72
|
- lib/tarantool/client/pool/member.rb
|
|
65
73
|
- lib/tarantool/client/pool/member_fork_safety.rb
|
|
74
|
+
- lib/tarantool/client/pool/member_role.rb
|
|
66
75
|
- lib/tarantool/client/prepared_statement.rb
|
|
67
76
|
- lib/tarantool/client/protocol/auth/chap_sha1.rb
|
|
68
77
|
- lib/tarantool/client/protocol/codec.rb
|
|
@@ -93,6 +102,7 @@ files:
|
|
|
93
102
|
- lib/tarantool/client/protocol/requests/upsert.rb
|
|
94
103
|
- lib/tarantool/client/protocol/requests/watch.rb
|
|
95
104
|
- lib/tarantool/client/protocol/response.rb
|
|
105
|
+
- lib/tarantool/client/row.rb
|
|
96
106
|
- lib/tarantool/client/schema.rb
|
|
97
107
|
- lib/tarantool/client/schema_cache.rb
|
|
98
108
|
- lib/tarantool/client/space_info.rb
|
|
@@ -107,11 +117,14 @@ files:
|
|
|
107
117
|
- lib/tarantool/client/transport/future.rb
|
|
108
118
|
- lib/tarantool/client/transport/handshake.rb
|
|
109
119
|
- lib/tarantool/client/transport/link.rb
|
|
120
|
+
- lib/tarantool/client/transport/link_events.rb
|
|
110
121
|
- lib/tarantool/client/transport/link_state.rb
|
|
111
122
|
- lib/tarantool/client/transport/pending_requests.rb
|
|
112
123
|
- lib/tarantool/client/transport/stream_ids.rb
|
|
113
124
|
- lib/tarantool/client/transport/timed_lock.rb
|
|
114
125
|
- lib/tarantool/client/transport/timed_read.rb
|
|
126
|
+
- lib/tarantool/client/tuple_mapping.rb
|
|
127
|
+
- lib/tarantool/client/tuple_shape.rb
|
|
115
128
|
- lib/tarantool/client/uuid.rb
|
|
116
129
|
- lib/tarantool/client/version.rb
|
|
117
130
|
- lib/tarantool/client/watcher.rb
|