valkey-glide-rb 0.9.0.pre.rc1
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/.rubocop.yml +69 -0
- data/.rubocop_todo.yml +22 -0
- data/AGENTS.md +224 -0
- data/CLAUDE.md +130 -0
- data/CONTRIBUTING.md +115 -0
- data/DEVELOPER.md +453 -0
- data/README.md +268 -0
- data/Rakefile +126 -0
- data/examples/README.md +55 -0
- data/examples/cluster.rb +24 -0
- data/examples/opentelemetry.rb +50 -0
- data/examples/pipelining.rb +29 -0
- data/examples/standalone.rb +22 -0
- data/examples/statistics.rb +24 -0
- data/lib/valkey/bindings.rb +319 -0
- data/lib/valkey/commands/bitmap_commands.rb +86 -0
- data/lib/valkey/commands/cluster_commands.rb +259 -0
- data/lib/valkey/commands/connection_commands.rb +318 -0
- data/lib/valkey/commands/function_commands.rb +255 -0
- data/lib/valkey/commands/generic_commands.rb +525 -0
- data/lib/valkey/commands/geo_commands.rb +87 -0
- data/lib/valkey/commands/hash_commands.rb +592 -0
- data/lib/valkey/commands/hyper_log_log_commands.rb +51 -0
- data/lib/valkey/commands/json_commands.rb +389 -0
- data/lib/valkey/commands/list_commands.rb +348 -0
- data/lib/valkey/commands/module_commands.rb +125 -0
- data/lib/valkey/commands/pubsub_commands.rb +237 -0
- data/lib/valkey/commands/scripting_commands.rb +287 -0
- data/lib/valkey/commands/server_commands.rb +961 -0
- data/lib/valkey/commands/set_commands.rb +220 -0
- data/lib/valkey/commands/sorted_set_commands.rb +971 -0
- data/lib/valkey/commands/stream_commands.rb +636 -0
- data/lib/valkey/commands/string_commands.rb +371 -0
- data/lib/valkey/commands/transaction_commands.rb +175 -0
- data/lib/valkey/commands/vector_search_commands.rb +271 -0
- data/lib/valkey/commands.rb +68 -0
- data/lib/valkey/errors.rb +41 -0
- data/lib/valkey/native/aarch64-unknown-linux-gnu/libglide_ffi.so +0 -0
- data/lib/valkey/native/x86_64-unknown-linux-gnu/libglide_ffi.so +0 -0
- data/lib/valkey/opentelemetry.rb +207 -0
- data/lib/valkey/pipeline.rb +20 -0
- data/lib/valkey/pubsub_callback.rb +10 -0
- data/lib/valkey/request_error_type.rb +10 -0
- data/lib/valkey/request_type.rb +436 -0
- data/lib/valkey/response_type.rb +20 -0
- data/lib/valkey/utils.rb +267 -0
- data/lib/valkey/version.rb +5 -0
- data/lib/valkey.rb +617 -0
- metadata +107 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Valkey
|
|
4
|
+
module Bindings
|
|
5
|
+
extend FFI::Library
|
|
6
|
+
|
|
7
|
+
# Determine platform-specific library extension and directory name
|
|
8
|
+
def self.platform_info
|
|
9
|
+
os = if FFI::Platform.mac?
|
|
10
|
+
"darwin"
|
|
11
|
+
elsif FFI::Platform.windows?
|
|
12
|
+
"windows"
|
|
13
|
+
else
|
|
14
|
+
"linux"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Detect architecture
|
|
18
|
+
arch = case RbConfig::CONFIG["host_cpu"]
|
|
19
|
+
when /x86_64|amd64/i
|
|
20
|
+
"x86_64"
|
|
21
|
+
when /aarch64|arm64/i
|
|
22
|
+
"aarch64"
|
|
23
|
+
when /i[3-6]86/i
|
|
24
|
+
"x86"
|
|
25
|
+
else
|
|
26
|
+
RbConfig::CONFIG["host_cpu"]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
lib_ext = case os
|
|
30
|
+
when "darwin"
|
|
31
|
+
"dylib"
|
|
32
|
+
when "windows"
|
|
33
|
+
"dll"
|
|
34
|
+
else
|
|
35
|
+
"so"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Platform directory name matches Rust target triple convention
|
|
39
|
+
platform_dir = case os
|
|
40
|
+
when "darwin"
|
|
41
|
+
"#{arch}-apple-darwin"
|
|
42
|
+
when "linux"
|
|
43
|
+
"#{arch}-unknown-linux-gnu"
|
|
44
|
+
when "windows"
|
|
45
|
+
"#{arch}-pc-windows-msvc"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
{ os: os, arch: arch, lib_ext: lib_ext, platform_dir: platform_dir }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
platform = platform_info
|
|
52
|
+
lib_ext = platform[:lib_ext]
|
|
53
|
+
platform_dir = platform[:platform_dir]
|
|
54
|
+
|
|
55
|
+
# Look for the native library in the following locations (in order):
|
|
56
|
+
# 1. valkey-glide submodule build output (development/source builds)
|
|
57
|
+
# 2. Platform-specific bundled library in lib/valkey/native/{platform}/ (for gem distribution)
|
|
58
|
+
# 3. Legacy bundled library in lib/valkey (fallback for old gem structure)
|
|
59
|
+
lib_paths = [
|
|
60
|
+
# Submodule build output (release) - from lib/valkey/ go up 2 levels to repo root
|
|
61
|
+
File.expand_path("../../valkey-glide/ffi/target/release/libglide_ffi.#{lib_ext}", __dir__),
|
|
62
|
+
# Submodule build output (debug)
|
|
63
|
+
File.expand_path("../../valkey-glide/ffi/target/debug/libglide_ffi.#{lib_ext}", __dir__),
|
|
64
|
+
# Platform-specific bundled library (for gem distribution)
|
|
65
|
+
File.expand_path("./native/#{platform_dir}/libglide_ffi.#{lib_ext}", __dir__),
|
|
66
|
+
# Legacy bundled library (fallback)
|
|
67
|
+
File.expand_path("./libglide_ffi.#{lib_ext}", __dir__)
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
lib_path = lib_paths.find { |path| File.exist?(path) }
|
|
71
|
+
|
|
72
|
+
unless lib_path
|
|
73
|
+
raise LoadError, <<~ERROR
|
|
74
|
+
Could not find libglide_ffi native library for platform: #{platform_dir}
|
|
75
|
+
|
|
76
|
+
Searched in:
|
|
77
|
+
#{lib_paths.map { |p| " - #{p}" }.join("\n")}
|
|
78
|
+
|
|
79
|
+
To build from source:
|
|
80
|
+
1. Initialize the submodule: git submodule update --init --recursive
|
|
81
|
+
2. Build the FFI library: cd valkey-glide/ffi && cargo build --release
|
|
82
|
+
|
|
83
|
+
Detected platform: OS=#{platform[:os]}, Arch=#{platform[:arch]}
|
|
84
|
+
ERROR
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
ffi_lib lib_path
|
|
88
|
+
|
|
89
|
+
class ClientType < FFI::Struct
|
|
90
|
+
layout(
|
|
91
|
+
:tag, :uint # 0 = AsyncClient, 1 = SyncClient
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class ConnectionResponse < FFI::Struct
|
|
96
|
+
layout(
|
|
97
|
+
:conn_ptr, :pointer, # *const c_void
|
|
98
|
+
:connection_error_message, :string # *const c_char (null-terminated C string)
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class CommandError < FFI::Struct
|
|
103
|
+
layout(
|
|
104
|
+
:command_error_message, :string,
|
|
105
|
+
:command_error_type, :int # Assuming RequestErrorType is repr(C) enum
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class BatchOptionsInfo < FFI::Struct
|
|
110
|
+
layout(
|
|
111
|
+
:retry_server_error, :bool,
|
|
112
|
+
:retry_connection_error, :bool,
|
|
113
|
+
:has_timeout, :bool,
|
|
114
|
+
:timeout, :uint, # Assuming u32 is represented as uint in C
|
|
115
|
+
:route_info, :pointer # *const RouteInfo
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class CmdInfo < FFI::Struct
|
|
120
|
+
layout(
|
|
121
|
+
:request_type, :int, # Assuming RequestType is repr(C) enum
|
|
122
|
+
:args, :pointer, # *const *const u8 (pointer to array of pointers to args)
|
|
123
|
+
:arg_count, :ulong, # usize (number of arguments)
|
|
124
|
+
:args_len, :pointer # *const usize (pointer to array of argument lengths)
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
class ScriptHashBuffer < FFI::Struct
|
|
129
|
+
layout(
|
|
130
|
+
:ptr, :pointer, # *mut u8 (pointer to the script hash)
|
|
131
|
+
:len, :ulong, # usize (length of the script hash)
|
|
132
|
+
:capacity, :ulong # usize (capacity of the buffer)
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
class BatchInfo < FFI::Struct
|
|
137
|
+
layout(
|
|
138
|
+
:cmd_count, :ulong, # usize
|
|
139
|
+
:cmds, :pointer, # *const *const CmdInfo
|
|
140
|
+
:is_atomic, :bool # bool
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
class CommandResponse < FFI::Struct
|
|
145
|
+
layout(
|
|
146
|
+
:response_type, :int, # Assuming ResponseType is repr(C) enum
|
|
147
|
+
:int_value, :int64,
|
|
148
|
+
:float_value, :double,
|
|
149
|
+
:bool_value, :bool,
|
|
150
|
+
:string_value, :pointer, # points to C string
|
|
151
|
+
:string_value_len, :long,
|
|
152
|
+
:array_value, :pointer, # points to CommandResponse array
|
|
153
|
+
:array_value_len, :long,
|
|
154
|
+
:map_key, :pointer, # CommandResponse*
|
|
155
|
+
:map_value, :pointer, # CommandResponse*
|
|
156
|
+
:sets_value, :pointer, # CommandResponse*
|
|
157
|
+
:sets_value_len, :long,
|
|
158
|
+
:arena_ptr, :pointer # *mut c_void - arena allocator pointer
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
callback :success_callback, %i[ulong pointer], :void
|
|
163
|
+
callback :failure_callback, %i[ulong string int], :void
|
|
164
|
+
|
|
165
|
+
class AsyncClientData < FFI::Struct
|
|
166
|
+
layout(
|
|
167
|
+
:success_callback, :success_callback,
|
|
168
|
+
:failure_callback, :failure_callback
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class ClientData < FFI::Union
|
|
173
|
+
layout(
|
|
174
|
+
:async_client, AsyncClientData
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
class CommandResult < FFI::Struct
|
|
179
|
+
layout(
|
|
180
|
+
:response, CommandResponse.by_ref,
|
|
181
|
+
:command_error, CommandError.by_ref,
|
|
182
|
+
:arena, :pointer # *mut ResponseArena
|
|
183
|
+
)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
callback :pubsub_callback, [
|
|
187
|
+
:ulong, # client_ptr
|
|
188
|
+
:int, # kind (PushKind enum)
|
|
189
|
+
:pointer, :long, # message + length
|
|
190
|
+
:pointer, :long, # channel + length
|
|
191
|
+
:pointer, :long # pattern + length
|
|
192
|
+
], :void
|
|
193
|
+
|
|
194
|
+
attach_function :create_client, [
|
|
195
|
+
:pointer, # *const u8 (connection_request_bytes)
|
|
196
|
+
:ulong, # usize (connection_request_len)
|
|
197
|
+
ClientType.by_ref, # *const ClientType
|
|
198
|
+
:pubsub_callback # callback
|
|
199
|
+
], :pointer # *const ConnectionResponse
|
|
200
|
+
|
|
201
|
+
attach_function :create_client_from_uri, [
|
|
202
|
+
:string, # *const c_char (uri_str)
|
|
203
|
+
:string, # *const c_char (extra_options_json)
|
|
204
|
+
ClientType.by_ref, # *const ClientType
|
|
205
|
+
:pubsub_callback # callback
|
|
206
|
+
], :pointer # *const ConnectionResponse
|
|
207
|
+
|
|
208
|
+
attach_function :free_connection_response, [
|
|
209
|
+
:pointer # *mut ConnectionResponse
|
|
210
|
+
], :void
|
|
211
|
+
|
|
212
|
+
attach_function :close_client, [
|
|
213
|
+
:pointer # client_adapter_ptr
|
|
214
|
+
], :void
|
|
215
|
+
|
|
216
|
+
attach_function :command, [
|
|
217
|
+
:pointer, # client_adapter_ptr
|
|
218
|
+
:ulong, # request_id
|
|
219
|
+
:int, # command_type
|
|
220
|
+
:ulong, # arg_count
|
|
221
|
+
:pointer, # args (pointer to usize[])
|
|
222
|
+
:pointer, # args_len (pointer to c_ulong[])
|
|
223
|
+
:pointer, # route_bytes
|
|
224
|
+
:ulong, # route_bytes_len
|
|
225
|
+
:ulong # span_ptr (u64)
|
|
226
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
227
|
+
|
|
228
|
+
attach_function :batch, [
|
|
229
|
+
:pointer, # client_ptr
|
|
230
|
+
:ulong, # callback_index
|
|
231
|
+
BatchInfo.by_ref, # *const BatchInfo
|
|
232
|
+
:bool, # raise_on_error
|
|
233
|
+
:pointer, # *const BatchOptionsInfo
|
|
234
|
+
:ulong # span_ptr (u64)
|
|
235
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
236
|
+
|
|
237
|
+
attach_function :store_script, [
|
|
238
|
+
:pointer, # *const u8 (script_bytes)
|
|
239
|
+
:ulong # usize (script_len)
|
|
240
|
+
], :pointer # returns *mut ScriptHashBuffer
|
|
241
|
+
|
|
242
|
+
attach_function :invoke_script, [
|
|
243
|
+
:pointer, # client_ptr
|
|
244
|
+
:ulong, # request_id
|
|
245
|
+
:pointer, # hash (pointer to C string)
|
|
246
|
+
:ulong, # keys_count (number of keys)
|
|
247
|
+
:pointer, # keys (pointer to usize[])
|
|
248
|
+
:pointer, # keys_len (pointer to c_ulong[])
|
|
249
|
+
:ulong, # args_count (number of args)
|
|
250
|
+
:pointer, # args (pointer to usize[])
|
|
251
|
+
:pointer, # args_len (pointer to c_ulong[])
|
|
252
|
+
:pointer, # route_bytes (pointer to u8)
|
|
253
|
+
:ulong, # route_bytes_len (usize)
|
|
254
|
+
:uint64 # span_ptr (OpenTelemetry span pointer)
|
|
255
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
256
|
+
|
|
257
|
+
# OpenTelemetry structures
|
|
258
|
+
class OpenTelemetryTracesConfig < FFI::Struct
|
|
259
|
+
layout(
|
|
260
|
+
:endpoint, :pointer, # const char* (trace collector endpoint)
|
|
261
|
+
:has_sample_percentage, :bool, # whether sample_percentage is set
|
|
262
|
+
:sample_percentage, :uint32 # sampling percentage (0-100)
|
|
263
|
+
)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
class OpenTelemetryMetricsConfig < FFI::Struct
|
|
267
|
+
layout(
|
|
268
|
+
:endpoint, :pointer # const char* (metrics collector endpoint)
|
|
269
|
+
)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
class OpenTelemetryConfig < FFI::Struct
|
|
273
|
+
layout(
|
|
274
|
+
:traces, :pointer, # OpenTelemetryTracesConfig*
|
|
275
|
+
:metrics, :pointer, # OpenTelemetryMetricsConfig*
|
|
276
|
+
:has_flush_interval_ms, :bool, # whether flush_interval_ms is set
|
|
277
|
+
:flush_interval_ms, :int64 # flush interval in milliseconds
|
|
278
|
+
)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Statistics structure
|
|
282
|
+
class Statistics < FFI::Struct
|
|
283
|
+
layout(
|
|
284
|
+
:total_connections, :ulong,
|
|
285
|
+
:total_clients, :ulong,
|
|
286
|
+
:total_values_compressed, :ulong,
|
|
287
|
+
:total_values_decompressed, :ulong,
|
|
288
|
+
:total_original_bytes, :ulong,
|
|
289
|
+
:total_bytes_compressed, :ulong,
|
|
290
|
+
:total_bytes_decompressed, :ulong,
|
|
291
|
+
:compression_skipped_count, :ulong,
|
|
292
|
+
:subscription_out_of_sync_count, :ulong,
|
|
293
|
+
:subscription_last_sync_timestamp, :ulong
|
|
294
|
+
)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# OpenTelemetry functions
|
|
298
|
+
attach_function :init_open_telemetry, [
|
|
299
|
+
OpenTelemetryConfig.by_ref # OpenTelemetry configuration
|
|
300
|
+
], :pointer # returns error string or NULL on success
|
|
301
|
+
|
|
302
|
+
attach_function :free_c_string, [
|
|
303
|
+
:pointer # C string to free
|
|
304
|
+
], :void
|
|
305
|
+
|
|
306
|
+
attach_function :create_otel_span, [
|
|
307
|
+
:int # request_type (RequestType enum value)
|
|
308
|
+
], :uint64 # returns span pointer (u64) or 0 on failure
|
|
309
|
+
|
|
310
|
+
attach_function :create_batch_otel_span, [], :uint64 # returns span pointer (u64) or 0 on failure
|
|
311
|
+
|
|
312
|
+
attach_function :drop_otel_span, [
|
|
313
|
+
:uint64 # span_ptr to close
|
|
314
|
+
], :void
|
|
315
|
+
|
|
316
|
+
# Statistics function
|
|
317
|
+
attach_function :get_statistics, [], Statistics.by_value # returns statistics by value
|
|
318
|
+
end
|
|
319
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Valkey
|
|
4
|
+
module Commands
|
|
5
|
+
# this module contains commands related to BITMAP data type.
|
|
6
|
+
#
|
|
7
|
+
# @see https://valkey.io/commands/#bitmap
|
|
8
|
+
#
|
|
9
|
+
module BitmapCommands
|
|
10
|
+
# Sets or clears the bit at offset in the string value stored at key.
|
|
11
|
+
#
|
|
12
|
+
# @param [String] key
|
|
13
|
+
# @param [Integer] offset bit offset
|
|
14
|
+
# @param [Integer] value bit value `0` or `1`
|
|
15
|
+
# @return [Integer] the original bit value stored at `offset`
|
|
16
|
+
def setbit(key, offset, value)
|
|
17
|
+
send_command(RequestType::SET_BIT, [key, offset, value])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Returns the bit value at offset in the string value stored at key.
|
|
21
|
+
#
|
|
22
|
+
# @param [String] key
|
|
23
|
+
# @param [Integer] offset bit offset
|
|
24
|
+
# @return [Integer] `0` or `1`
|
|
25
|
+
def getbit(key, offset)
|
|
26
|
+
send_command(RequestType::GET_BIT, [key, offset])
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Count the number of set bits in a range of the string value stored at key.
|
|
30
|
+
#
|
|
31
|
+
# @param [String] key
|
|
32
|
+
# @param [Integer] start start index
|
|
33
|
+
# @param [Integer] stop stop index
|
|
34
|
+
# @param [String, Symbol] scale the scale of the offset range
|
|
35
|
+
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
|
|
36
|
+
# @return [Integer] the number of bits set to 1
|
|
37
|
+
def bitcount(key, start = 0, stop = -1, scale: nil)
|
|
38
|
+
args = [key, start, stop]
|
|
39
|
+
args << scale if scale
|
|
40
|
+
send_command(RequestType::BIT_COUNT, args)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Perform a bitwise operation between strings and store the resulting string in a key.
|
|
44
|
+
#
|
|
45
|
+
# @param [String] operation e.g. `and`, `or`, `xor`, `not`
|
|
46
|
+
# @param [String] destkey destination key
|
|
47
|
+
# @param [String, Array<String>] keys one or more source keys to perform `operation`
|
|
48
|
+
# @return [Integer] the length of the string stored in `destkey`
|
|
49
|
+
def bitop(operation, destkey, *keys)
|
|
50
|
+
keys.flatten!(1)
|
|
51
|
+
args = [operation, destkey]
|
|
52
|
+
args.concat(keys)
|
|
53
|
+
|
|
54
|
+
send_command(RequestType::BIT_OP, args)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def bitfield(key, *args)
|
|
58
|
+
send_command(RequestType::BIT_FIELD, [key] + args.map(&:to_s))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def bitfield_ro(key, *args)
|
|
62
|
+
send_command(RequestType::BIT_FIELD_READ_ONLY, [key] + args.map(&:to_s))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Return the position of the first bit set to 1 or 0 in a string.
|
|
66
|
+
#
|
|
67
|
+
# @param [String] key
|
|
68
|
+
# @param [Integer] bit whether to look for the first 1 or 0 bit
|
|
69
|
+
# @param [Integer] start start index
|
|
70
|
+
# @param [Integer] stop stop index
|
|
71
|
+
# @param [String, Symbol] scale the scale of the offset range
|
|
72
|
+
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
|
|
73
|
+
# @return [Integer] the position of the first 1/0 bit.
|
|
74
|
+
# -1 if looking for 1 and it is not found or start and stop are given.
|
|
75
|
+
def bitpos(key, bit, start = nil, stop = nil, scale: nil)
|
|
76
|
+
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
|
77
|
+
|
|
78
|
+
args = [key, bit]
|
|
79
|
+
args << start if start
|
|
80
|
+
args << stop if stop
|
|
81
|
+
args << scale if scale
|
|
82
|
+
send_command(RequestType::BIT_POS, args)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Valkey
|
|
4
|
+
module Commands
|
|
5
|
+
# This module contains commands related to Redis Cluster management.
|
|
6
|
+
#
|
|
7
|
+
# @see https://valkey.io/commands/#cluster
|
|
8
|
+
#
|
|
9
|
+
module ClusterCommands
|
|
10
|
+
# Send ASKING command to the server.
|
|
11
|
+
#
|
|
12
|
+
# @return [String] `"OK"`
|
|
13
|
+
def asking
|
|
14
|
+
send_command(RequestType::ASKING)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Add slots to the cluster.
|
|
18
|
+
#
|
|
19
|
+
# @param [Array<Integer>] slots array of slot numbers
|
|
20
|
+
# @return [String] `"OK"`
|
|
21
|
+
def cluster_addslots(*slots)
|
|
22
|
+
send_command(RequestType::CLUSTER_ADD_SLOTS, slots)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Add a range of slots to the cluster.
|
|
26
|
+
#
|
|
27
|
+
# @param [Integer] start_slot starting slot number
|
|
28
|
+
# @param [Integer] end_slot ending slot number
|
|
29
|
+
# @return [String] `"OK"`
|
|
30
|
+
def cluster_addslotsrange(start_slot, end_slot)
|
|
31
|
+
send_command(RequestType::CLUSTER_ADD_SLOTS_RANGE, [start_slot, end_slot])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Bump the epoch of the cluster.
|
|
35
|
+
#
|
|
36
|
+
# @return [String] `"OK"`
|
|
37
|
+
def cluster_bumpepoch
|
|
38
|
+
send_command(RequestType::CLUSTER_BUMP_EPOCH)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Count failure reports for a node.
|
|
42
|
+
#
|
|
43
|
+
# @param [String] node_id the node ID
|
|
44
|
+
# @return [Integer] number of failure reports
|
|
45
|
+
def cluster_count_failure_reports(node_id)
|
|
46
|
+
send_command(RequestType::CLUSTER_COUNT_FAILURE_REPORTS, [node_id])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Count keys in a specific slot.
|
|
50
|
+
#
|
|
51
|
+
# @param [Integer] slot the slot number
|
|
52
|
+
# @return [Integer] number of keys in the slot
|
|
53
|
+
def cluster_countkeysinslot(slot)
|
|
54
|
+
send_command(RequestType::CLUSTER_COUNT_KEYS_IN_SLOT, [slot])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Delete slots from the cluster.
|
|
58
|
+
#
|
|
59
|
+
# @param [Array<Integer>] slots array of slot numbers
|
|
60
|
+
# @return [String] `"OK"`
|
|
61
|
+
def cluster_delslots(*slots)
|
|
62
|
+
send_command(RequestType::CLUSTER_DEL_SLOTS, slots)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Delete a range of slots from the cluster.
|
|
66
|
+
#
|
|
67
|
+
# @param [Integer] start_slot starting slot number
|
|
68
|
+
# @param [Integer] end_slot ending slot number
|
|
69
|
+
# @return [String] `"OK"`
|
|
70
|
+
def cluster_delslotsrange(start_slot, end_slot)
|
|
71
|
+
send_command(RequestType::CLUSTER_DEL_SLOTS_RANGE, [start_slot, end_slot])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Force a failover of the cluster.
|
|
75
|
+
#
|
|
76
|
+
# @param [String] force force the failover
|
|
77
|
+
# @return [String] `"OK"`
|
|
78
|
+
def cluster_failover(force = nil)
|
|
79
|
+
args = []
|
|
80
|
+
args << "FORCE" if force
|
|
81
|
+
send_command(RequestType::CLUSTER_FAILOVER, args)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Flush all slots from the cluster.
|
|
85
|
+
#
|
|
86
|
+
# @return [String] `"OK"`
|
|
87
|
+
def cluster_flushslots
|
|
88
|
+
send_command(RequestType::CLUSTER_FLUSH_SLOTS)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Remove a node from the cluster.
|
|
92
|
+
#
|
|
93
|
+
# @param [String] node_id the node ID to forget
|
|
94
|
+
# @return [String] `"OK"`
|
|
95
|
+
def cluster_forget(node_id)
|
|
96
|
+
send_command(RequestType::CLUSTER_FORGET, [node_id])
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Get keys in a specific slot.
|
|
100
|
+
#
|
|
101
|
+
# @param [Integer] slot the slot number
|
|
102
|
+
# @param [Integer] count maximum number of keys to return
|
|
103
|
+
# @return [Array<String>] array of keys
|
|
104
|
+
def cluster_getkeysinslot(slot, count)
|
|
105
|
+
send_command(RequestType::CLUSTER_GET_KEYS_IN_SLOT, [slot, count])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Get information about the cluster.
|
|
109
|
+
#
|
|
110
|
+
# @return [Hash<String, String>] cluster information
|
|
111
|
+
def cluster_info
|
|
112
|
+
send_command(RequestType::CLUSTER_INFO) do |reply|
|
|
113
|
+
Utils::HashifyInfo.call(reply)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Get the slot for a key.
|
|
118
|
+
#
|
|
119
|
+
# @param [String] key the key name
|
|
120
|
+
# @return [Integer] slot number
|
|
121
|
+
def cluster_keyslot(key)
|
|
122
|
+
send_command(RequestType::CLUSTER_KEY_SLOT, [key])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Get information about cluster links.
|
|
126
|
+
#
|
|
127
|
+
# @return [Array<Hash>] array of link information
|
|
128
|
+
def cluster_links
|
|
129
|
+
send_command(RequestType::CLUSTER_LINKS)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Meet another node in the cluster.
|
|
133
|
+
#
|
|
134
|
+
# @param [String] ip IP address of the node
|
|
135
|
+
# @param [Integer] port port of the node
|
|
136
|
+
# @return [String] `"OK"`
|
|
137
|
+
def cluster_meet(ip, port)
|
|
138
|
+
send_command(RequestType::CLUSTER_MEET, [ip, port])
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Get the ID of the current node.
|
|
142
|
+
#
|
|
143
|
+
# @return [String] node ID
|
|
144
|
+
def cluster_myid
|
|
145
|
+
send_command(RequestType::CLUSTER_MY_ID)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Get the shard ID of the current node.
|
|
149
|
+
#
|
|
150
|
+
# @return [String] shard ID
|
|
151
|
+
def cluster_myshardid
|
|
152
|
+
send_command(RequestType::CLUSTER_MY_SHARD_ID)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Get information about all nodes in the cluster.
|
|
156
|
+
#
|
|
157
|
+
# @return [Array<Hash>] array of node information
|
|
158
|
+
def cluster_nodes
|
|
159
|
+
send_command(RequestType::CLUSTER_NODES) do |reply|
|
|
160
|
+
Utils::HashifyClusterNodes.call(reply)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Get information about replica nodes.
|
|
165
|
+
#
|
|
166
|
+
# @param [String] node_id the master node ID
|
|
167
|
+
# @return [Array<Hash>] array of replica information
|
|
168
|
+
def cluster_replicas(node_id)
|
|
169
|
+
send_command(RequestType::CLUSTER_REPLICAS, [node_id]) do |reply|
|
|
170
|
+
Utils::HashifyClusterSlaves.call(reply)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Set a node as a replica of another node.
|
|
175
|
+
#
|
|
176
|
+
# @param [String] node_id the master node ID
|
|
177
|
+
# @return [String] `"OK"`
|
|
178
|
+
def cluster_replicate(node_id)
|
|
179
|
+
send_command(RequestType::CLUSTER_REPLICATE, [node_id])
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Reset the cluster.
|
|
183
|
+
#
|
|
184
|
+
# @param [String] hard hard reset
|
|
185
|
+
# @return [String] `"OK"`
|
|
186
|
+
def cluster_reset(hard = nil)
|
|
187
|
+
args = []
|
|
188
|
+
args << "HARD" if hard
|
|
189
|
+
send_command(RequestType::CLUSTER_RESET, args)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Save the cluster configuration.
|
|
193
|
+
#
|
|
194
|
+
# @return [String] `"OK"`
|
|
195
|
+
def cluster_saveconfig
|
|
196
|
+
send_command(RequestType::CLUSTER_SAVE_CONFIG)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Set the config epoch for a node.
|
|
200
|
+
#
|
|
201
|
+
# @param [Integer] epoch the config epoch
|
|
202
|
+
# @return [String] `"OK"`
|
|
203
|
+
def cluster_set_config_epoch(epoch)
|
|
204
|
+
send_command(RequestType::CLUSTER_SET_CONFIG_EPOCH, [epoch])
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Set the state of a slot.
|
|
208
|
+
#
|
|
209
|
+
# @param [Integer] slot the slot number
|
|
210
|
+
# @param [String] state the state (importing, migrating, node, stable)
|
|
211
|
+
# @param [String] node_id the node ID (optional)
|
|
212
|
+
# @return [String] `"OK"`
|
|
213
|
+
def cluster_setslot(slot, state, node_id = nil)
|
|
214
|
+
args = [slot, state]
|
|
215
|
+
args << node_id if node_id
|
|
216
|
+
send_command(RequestType::CLUSTER_SETSLOT, args)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Get information about cluster shards.
|
|
220
|
+
#
|
|
221
|
+
# @return [Array<Hash>] array of shard information
|
|
222
|
+
def cluster_shards
|
|
223
|
+
send_command(RequestType::CLUSTER_SHARDS)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Get information about slave nodes (deprecated, use cluster_replicas).
|
|
227
|
+
#
|
|
228
|
+
# @return [Array<Hash>] array of slave information
|
|
229
|
+
def cluster_slaves(node_id)
|
|
230
|
+
send_command(RequestType::CLUSTER_SLAVES, [node_id]) do |reply|
|
|
231
|
+
Utils::HashifyClusterSlaves.call(reply)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Get information about cluster slots.
|
|
236
|
+
#
|
|
237
|
+
# @return [Array<Hash>] array of slot information
|
|
238
|
+
def cluster_slots
|
|
239
|
+
send_command(RequestType::CLUSTER_SLOTS) do |reply|
|
|
240
|
+
Utils::HashifyClusterSlots.call(reply)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Set the connection to read-only mode.
|
|
245
|
+
#
|
|
246
|
+
# @return [String] "OK"
|
|
247
|
+
def readonly
|
|
248
|
+
send_command(RequestType::READ_ONLY)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Set the connection to read-write mode.
|
|
252
|
+
#
|
|
253
|
+
# @return [String] "OK"
|
|
254
|
+
def readwrite
|
|
255
|
+
send_command(RequestType::READ_WRITE)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|