tarantool-client 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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +24 -0
  3. data/LICENSE +21 -0
  4. data/README.md +222 -0
  5. data/lib/tarantool/client/backoff.rb +23 -0
  6. data/lib/tarantool/client/box_error.rb +15 -0
  7. data/lib/tarantool/client/callback_guard.rb +23 -0
  8. data/lib/tarantool/client/configuration.rb +71 -0
  9. data/lib/tarantool/client/errors.rb +56 -0
  10. data/lib/tarantool/client/fork_safety.rb +42 -0
  11. data/lib/tarantool/client/index_info.rb +27 -0
  12. data/lib/tarantool/client/interval.rb +25 -0
  13. data/lib/tarantool/client/operations.rb +89 -0
  14. data/lib/tarantool/client/pool/member.rb +141 -0
  15. data/lib/tarantool/client/pool/member_fork_safety.rb +34 -0
  16. data/lib/tarantool/client/pool.rb +127 -0
  17. data/lib/tarantool/client/prepared_statement.rb +25 -0
  18. data/lib/tarantool/client/protocol/auth/chap_sha1.rb +28 -0
  19. data/lib/tarantool/client/protocol/codec.rb +79 -0
  20. data/lib/tarantool/client/protocol/constants.rb +105 -0
  21. data/lib/tarantool/client/protocol/extensions/datetime.rb +39 -0
  22. data/lib/tarantool/client/protocol/extensions/decimal.rb +73 -0
  23. data/lib/tarantool/client/protocol/extensions/error.rb +33 -0
  24. data/lib/tarantool/client/protocol/extensions/interval.rb +59 -0
  25. data/lib/tarantool/client/protocol/extensions/uuid.rb +29 -0
  26. data/lib/tarantool/client/protocol/extensions.rb +27 -0
  27. data/lib/tarantool/client/protocol/greeting.rb +21 -0
  28. data/lib/tarantool/client/protocol/requests/auth.rb +23 -0
  29. data/lib/tarantool/client/protocol/requests/begin.rb +30 -0
  30. data/lib/tarantool/client/protocol/requests/call.rb +16 -0
  31. data/lib/tarantool/client/protocol/requests/commit.rb +16 -0
  32. data/lib/tarantool/client/protocol/requests/delete.rb +19 -0
  33. data/lib/tarantool/client/protocol/requests/eval.rb +16 -0
  34. data/lib/tarantool/client/protocol/requests/execute.rb +21 -0
  35. data/lib/tarantool/client/protocol/requests/id.rb +16 -0
  36. data/lib/tarantool/client/protocol/requests/insert.rb +16 -0
  37. data/lib/tarantool/client/protocol/requests/ping.rb +17 -0
  38. data/lib/tarantool/client/protocol/requests/prepare.rb +16 -0
  39. data/lib/tarantool/client/protocol/requests/replace.rb +16 -0
  40. data/lib/tarantool/client/protocol/requests/rollback.rb +16 -0
  41. data/lib/tarantool/client/protocol/requests/select.rb +32 -0
  42. data/lib/tarantool/client/protocol/requests/unwatch.rb +16 -0
  43. data/lib/tarantool/client/protocol/requests/update.rb +24 -0
  44. data/lib/tarantool/client/protocol/requests/upsert.rb +19 -0
  45. data/lib/tarantool/client/protocol/requests/watch.rb +16 -0
  46. data/lib/tarantool/client/protocol/response.rb +36 -0
  47. data/lib/tarantool/client/schema.rb +69 -0
  48. data/lib/tarantool/client/schema_cache.rb +54 -0
  49. data/lib/tarantool/client/space_info.rb +27 -0
  50. data/lib/tarantool/client/sql_result.rb +24 -0
  51. data/lib/tarantool/client/stream.rb +130 -0
  52. data/lib/tarantool/client/thread_join.rb +19 -0
  53. data/lib/tarantool/client/transaction_schema.rb +57 -0
  54. data/lib/tarantool/client/transaction_scope.rb +28 -0
  55. data/lib/tarantool/client/transport/connection.rb +141 -0
  56. data/lib/tarantool/client/transport/deadline.rb +17 -0
  57. data/lib/tarantool/client/transport/frame_writer.rb +41 -0
  58. data/lib/tarantool/client/transport/future.rb +60 -0
  59. data/lib/tarantool/client/transport/handshake.rb +36 -0
  60. data/lib/tarantool/client/transport/link.rb +150 -0
  61. data/lib/tarantool/client/transport/link_state.rb +115 -0
  62. data/lib/tarantool/client/transport/pending_requests.rb +55 -0
  63. data/lib/tarantool/client/transport/stream_ids.rb +20 -0
  64. data/lib/tarantool/client/transport/timed_lock.rb +53 -0
  65. data/lib/tarantool/client/transport/timed_read.rb +31 -0
  66. data/lib/tarantool/client/uuid.rb +20 -0
  67. data/lib/tarantool/client/version.rb +7 -0
  68. data/lib/tarantool/client/watcher.rb +37 -0
  69. data/lib/tarantool/client/watchers/dispatcher.rb +40 -0
  70. data/lib/tarantool/client/watchers.rb +137 -0
  71. data/lib/tarantool/client.rb +216 -0
  72. metadata +148 -0
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'msgpack'
4
+ require 'bigdecimal'
5
+
6
+ require_relative 'client/version'
7
+ require_relative 'client/errors'
8
+ require_relative 'client/configuration'
9
+ require_relative 'client/backoff'
10
+ require_relative 'client/thread_join'
11
+ require_relative 'client/protocol/constants'
12
+ require_relative 'client/box_error'
13
+ require_relative 'client/uuid'
14
+ require_relative 'client/interval'
15
+ require_relative 'client/protocol/extensions'
16
+ require_relative 'client/protocol/extensions/error'
17
+ require_relative 'client/protocol/extensions/uuid'
18
+ require_relative 'client/protocol/extensions/decimal'
19
+ require_relative 'client/protocol/extensions/datetime'
20
+ require_relative 'client/protocol/extensions/interval'
21
+ require_relative 'client/protocol/response'
22
+ require_relative 'client/protocol/codec'
23
+ require_relative 'client/protocol/greeting'
24
+ require_relative 'client/protocol/auth/chap_sha1'
25
+ require_relative 'client/protocol/requests/ping'
26
+ require_relative 'client/protocol/requests/select'
27
+ require_relative 'client/protocol/requests/insert'
28
+ require_relative 'client/protocol/requests/replace'
29
+ require_relative 'client/protocol/requests/update'
30
+ require_relative 'client/protocol/requests/upsert'
31
+ require_relative 'client/protocol/requests/delete'
32
+ require_relative 'client/protocol/requests/call'
33
+ require_relative 'client/protocol/requests/eval'
34
+ require_relative 'client/protocol/requests/execute'
35
+ require_relative 'client/protocol/requests/prepare'
36
+ require_relative 'client/protocol/requests/begin'
37
+ require_relative 'client/protocol/requests/commit'
38
+ require_relative 'client/protocol/requests/rollback'
39
+ require_relative 'client/protocol/requests/auth'
40
+ require_relative 'client/protocol/requests/id'
41
+ require_relative 'client/protocol/requests/watch'
42
+ require_relative 'client/protocol/requests/unwatch'
43
+ require_relative 'client/transport/future'
44
+ require_relative 'client/transport/pending_requests'
45
+ require_relative 'client/transport/stream_ids'
46
+ require_relative 'client/transport/deadline'
47
+ require_relative 'client/transport/timed_lock'
48
+ require_relative 'client/transport/timed_read'
49
+ require_relative 'client/transport/frame_writer'
50
+ require_relative 'client/transport/handshake'
51
+ require_relative 'client/transport/connection'
52
+ require_relative 'client/transport/link_state'
53
+ require_relative 'client/transport/link'
54
+ require_relative 'client/index_info'
55
+ require_relative 'client/space_info'
56
+ require_relative 'client/schema'
57
+ require_relative 'client/schema_cache'
58
+ require_relative 'client/sql_result'
59
+ require_relative 'client/prepared_statement'
60
+ require_relative 'client/transaction_schema'
61
+ require_relative 'client/operations'
62
+ require_relative 'client/transaction_scope'
63
+ require_relative 'client/stream'
64
+ require_relative 'client/callback_guard'
65
+ require_relative 'client/watcher'
66
+ require_relative 'client/watchers'
67
+ require_relative 'client/watchers/dispatcher'
68
+ require_relative 'client/fork_safety'
69
+ require_relative 'client/pool'
70
+ require_relative 'client/pool/member_fork_safety'
71
+ require_relative 'client/pool/member'
72
+
73
+ module Tarantool
74
+ # Connection to one Tarantool instance. Safe to share between threads and fibers.
75
+ class Client
76
+ include Operations
77
+ include ForkSafety
78
+
79
+ attr_reader :config
80
+
81
+ # @api private
82
+ # Called when the connection is lost, before the first reconnect attempt, then again on the watcher
83
+ # dispatcher thread after every event of the lost connection and before any of the next one.
84
+ attr_writer :disconnect_handler
85
+
86
+ def initialize(uri = nil, **)
87
+ @config = Configuration.build(uri, **)
88
+ @pid = Process.pid
89
+ @reinit_lock = Mutex.new
90
+ open_link
91
+ rescue StandardError
92
+ @link&.close
93
+ raise
94
+ end
95
+
96
+ def server_version
97
+ ensure_fork_safe
98
+ @link.greeting.version
99
+ end
100
+
101
+ def connected?
102
+ @pid == Process.pid && @link.connected?
103
+ end
104
+
105
+ def transaction(isolation: :default, timeout: nil, &block)
106
+ ensure_fork_safe
107
+ TransactionScope.enter(self) do
108
+ stream = Stream.new(
109
+ connection: @link.connection, schema_cache: @schema_cache, id: @stream_ids.next,
110
+ request_timeout: @config.request_timeout
111
+ )
112
+ stream.transaction(isolation:, timeout:, &block)
113
+ end
114
+ end
115
+
116
+ # The block gets the current value first (nil if the key was never broadcast), then every
117
+ # change. It runs on a dispatcher thread shared by all watchers of this client, so a slow
118
+ # block delays the others; exceptions it raises are reported with warn. Calling #unwatch
119
+ # from another thread may still let one in-flight callback run. After a reconnect the block
120
+ # is called again with the current value.
121
+ def watch(key, &block)
122
+ raise ArgumentError, 'watch requires a block' unless block
123
+
124
+ ensure_fork_safe
125
+ @watchers.add(key, block)
126
+ end
127
+
128
+ def close
129
+ @link.close
130
+
131
+ @watchers.close
132
+ end
133
+
134
+ def inspect
135
+ "#<#{self.class.name} #{@config.address}>"
136
+ end
137
+
138
+ private
139
+
140
+ def link_hooks = { on_connect: method(:load_schema), on_ready: method(:resubscribe), on_lost: method(:lost) }
141
+
142
+ def perform(request, timeout: nil, schema_version: nil, on_push: nil)
143
+ ensure_fork_safe
144
+ @link.perform(request, timeout: timeout || @config.request_timeout, schema_version:, on_push:)
145
+ end
146
+
147
+ # Runs for every new connection before requests can use it. A new instance may reuse a schema
148
+ # version with other ids, so the old schema must never resolve a name for it.
149
+ def load_schema(connection)
150
+ @schema_cache.replace(Schema.fetch(connection, timeout: @config.request_timeout))
151
+ end
152
+
153
+ def resubscribe(connection)
154
+ @watchers.resubscribe(connection)
155
+ end
156
+
157
+ def lost
158
+ return unless @disconnect_handler
159
+
160
+ @disconnect_handler.call
161
+
162
+ @watchers.defer(&@disconnect_handler)
163
+ end
164
+
165
+ # Name-resolved requests carry the schema version they were resolved against, so the
166
+ # server rejects them (ER_WRONG_SCHEMA_VERSION) instead of running them on a stale id.
167
+ def perform_on_space(space, index, timeout: nil, &)
168
+ return perform(yield(space, index), timeout:) if space.is_a?(Integer) && index.is_a?(Integer)
169
+
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)
214
+ end
215
+ end
216
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tarantool-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Starlexxx
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-10-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bigdecimal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: msgpack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ description: 'Thread-safe IPROTO client for Tarantool 2.11+ and 3.x: CRUD by space
42
+ and index name, SQL, interactive transactions, push, watchers, background reconnect
43
+ and a role-aware pool.'
44
+ email:
45
+ - apavlovskiy088@gmail.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - CHANGELOG.md
51
+ - LICENSE
52
+ - README.md
53
+ - lib/tarantool/client.rb
54
+ - lib/tarantool/client/backoff.rb
55
+ - lib/tarantool/client/box_error.rb
56
+ - lib/tarantool/client/callback_guard.rb
57
+ - lib/tarantool/client/configuration.rb
58
+ - lib/tarantool/client/errors.rb
59
+ - lib/tarantool/client/fork_safety.rb
60
+ - lib/tarantool/client/index_info.rb
61
+ - lib/tarantool/client/interval.rb
62
+ - lib/tarantool/client/operations.rb
63
+ - lib/tarantool/client/pool.rb
64
+ - lib/tarantool/client/pool/member.rb
65
+ - lib/tarantool/client/pool/member_fork_safety.rb
66
+ - lib/tarantool/client/prepared_statement.rb
67
+ - lib/tarantool/client/protocol/auth/chap_sha1.rb
68
+ - lib/tarantool/client/protocol/codec.rb
69
+ - lib/tarantool/client/protocol/constants.rb
70
+ - lib/tarantool/client/protocol/extensions.rb
71
+ - lib/tarantool/client/protocol/extensions/datetime.rb
72
+ - lib/tarantool/client/protocol/extensions/decimal.rb
73
+ - lib/tarantool/client/protocol/extensions/error.rb
74
+ - lib/tarantool/client/protocol/extensions/interval.rb
75
+ - lib/tarantool/client/protocol/extensions/uuid.rb
76
+ - lib/tarantool/client/protocol/greeting.rb
77
+ - lib/tarantool/client/protocol/requests/auth.rb
78
+ - lib/tarantool/client/protocol/requests/begin.rb
79
+ - lib/tarantool/client/protocol/requests/call.rb
80
+ - lib/tarantool/client/protocol/requests/commit.rb
81
+ - lib/tarantool/client/protocol/requests/delete.rb
82
+ - lib/tarantool/client/protocol/requests/eval.rb
83
+ - lib/tarantool/client/protocol/requests/execute.rb
84
+ - lib/tarantool/client/protocol/requests/id.rb
85
+ - lib/tarantool/client/protocol/requests/insert.rb
86
+ - lib/tarantool/client/protocol/requests/ping.rb
87
+ - lib/tarantool/client/protocol/requests/prepare.rb
88
+ - lib/tarantool/client/protocol/requests/replace.rb
89
+ - lib/tarantool/client/protocol/requests/rollback.rb
90
+ - lib/tarantool/client/protocol/requests/select.rb
91
+ - lib/tarantool/client/protocol/requests/unwatch.rb
92
+ - lib/tarantool/client/protocol/requests/update.rb
93
+ - lib/tarantool/client/protocol/requests/upsert.rb
94
+ - lib/tarantool/client/protocol/requests/watch.rb
95
+ - lib/tarantool/client/protocol/response.rb
96
+ - lib/tarantool/client/schema.rb
97
+ - lib/tarantool/client/schema_cache.rb
98
+ - lib/tarantool/client/space_info.rb
99
+ - lib/tarantool/client/sql_result.rb
100
+ - lib/tarantool/client/stream.rb
101
+ - lib/tarantool/client/thread_join.rb
102
+ - lib/tarantool/client/transaction_schema.rb
103
+ - lib/tarantool/client/transaction_scope.rb
104
+ - lib/tarantool/client/transport/connection.rb
105
+ - lib/tarantool/client/transport/deadline.rb
106
+ - lib/tarantool/client/transport/frame_writer.rb
107
+ - lib/tarantool/client/transport/future.rb
108
+ - lib/tarantool/client/transport/handshake.rb
109
+ - lib/tarantool/client/transport/link.rb
110
+ - lib/tarantool/client/transport/link_state.rb
111
+ - lib/tarantool/client/transport/pending_requests.rb
112
+ - lib/tarantool/client/transport/stream_ids.rb
113
+ - lib/tarantool/client/transport/timed_lock.rb
114
+ - lib/tarantool/client/transport/timed_read.rb
115
+ - lib/tarantool/client/uuid.rb
116
+ - lib/tarantool/client/version.rb
117
+ - lib/tarantool/client/watcher.rb
118
+ - lib/tarantool/client/watchers.rb
119
+ - lib/tarantool/client/watchers/dispatcher.rb
120
+ homepage: https://github.com/Starlexxx/tarantool-ruby
121
+ licenses:
122
+ - MIT
123
+ metadata:
124
+ source_code_uri: https://github.com/Starlexxx/tarantool-ruby/tree/master/tarantool-client
125
+ changelog_uri: https://github.com/Starlexxx/tarantool-ruby/blob/master/tarantool-client/CHANGELOG.md
126
+ bug_tracker_uri: https://github.com/Starlexxx/tarantool-ruby/issues
127
+ homepage_uri: https://github.com/Starlexxx/tarantool-ruby
128
+ rubygems_mfa_required: 'true'
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '3.2'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubygems_version: 3.5.22
145
+ signing_key:
146
+ specification_version: 4
147
+ summary: IPROTO client for Tarantool 2.11+ and 3.x
148
+ test_files: []