mini-safe-lib 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/mini-safe-lib.gemspec +12 -0
- data/redis-5.4.1/CHANGELOG.md +693 -0
- data/redis-5.4.1/LICENSE +20 -0
- data/redis-5.4.1/README.md +453 -0
- data/redis-5.4.1/lib/redis/client.rb +131 -0
- data/redis-5.4.1/lib/redis/commands/bitmaps.rb +73 -0
- data/redis-5.4.1/lib/redis/commands/cluster.rb +28 -0
- data/redis-5.4.1/lib/redis/commands/connection.rb +53 -0
- data/redis-5.4.1/lib/redis/commands/geo.rb +84 -0
- data/redis-5.4.1/lib/redis/commands/hashes.rb +258 -0
- data/redis-5.4.1/lib/redis/commands/hyper_log_log.rb +37 -0
- data/redis-5.4.1/lib/redis/commands/keys.rb +459 -0
- data/redis-5.4.1/lib/redis/commands/lists.rb +339 -0
- data/redis-5.4.1/lib/redis/commands/pubsub.rb +81 -0
- data/redis-5.4.1/lib/redis/commands/scripting.rb +114 -0
- data/redis-5.4.1/lib/redis/commands/server.rb +188 -0
- data/redis-5.4.1/lib/redis/commands/sets.rb +218 -0
- data/redis-5.4.1/lib/redis/commands/sorted_sets.rb +922 -0
- data/redis-5.4.1/lib/redis/commands/streams.rb +409 -0
- data/redis-5.4.1/lib/redis/commands/strings.rb +314 -0
- data/redis-5.4.1/lib/redis/commands/transactions.rb +115 -0
- data/redis-5.4.1/lib/redis/commands.rb +239 -0
- data/redis-5.4.1/lib/redis/distributed.rb +1107 -0
- data/redis-5.4.1/lib/redis/errors.rb +67 -0
- data/redis-5.4.1/lib/redis/hash_ring.rb +89 -0
- data/redis-5.4.1/lib/redis/pipeline.rb +131 -0
- data/redis-5.4.1/lib/redis/subscribe.rb +126 -0
- data/redis-5.4.1/lib/redis/version.rb +5 -0
- data/redis-5.4.1/lib/redis.rb +344 -0
- metadata +70 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Redis
|
|
4
|
+
# Base error for all redis-rb errors.
|
|
5
|
+
class BaseError < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Raised by the connection when a protocol error occurs.
|
|
9
|
+
class ProtocolError < BaseError
|
|
10
|
+
def initialize(reply_type)
|
|
11
|
+
super(<<-EOS.gsub(/(?:^|\n)\s*/, " "))
|
|
12
|
+
Got '#{reply_type}' as initial reply byte.
|
|
13
|
+
If you're in a forking environment, such as Unicorn, you need to
|
|
14
|
+
connect to Redis after forking.
|
|
15
|
+
EOS
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Raised by the client when command execution returns an error reply.
|
|
20
|
+
class CommandError < BaseError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class PermissionError < CommandError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class WrongTypeError < CommandError
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class OutOfMemoryError < CommandError
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if defined?(RedisClient::NoScriptError)
|
|
33
|
+
class NoScriptError < CommandError
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Base error for connection related errors.
|
|
38
|
+
class BaseConnectionError < BaseError
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Raised when connection to a Redis server cannot be made.
|
|
42
|
+
class CannotConnectError < BaseConnectionError
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Raised when connection to a Redis server is lost.
|
|
46
|
+
class ConnectionError < BaseConnectionError
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Raised when performing I/O times out.
|
|
50
|
+
class TimeoutError < BaseConnectionError
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Raised when the connection was inherited by a child process.
|
|
54
|
+
class InheritedError < BaseConnectionError
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Generally raised during Redis failover scenarios
|
|
58
|
+
class ReadOnlyError < BaseConnectionError
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Raised when client options are invalid.
|
|
62
|
+
class InvalidClientOptionError < BaseError
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class SubscriptionError < BaseError
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'zlib'
|
|
4
|
+
require 'digest/md5'
|
|
5
|
+
|
|
6
|
+
class Redis
|
|
7
|
+
class HashRing
|
|
8
|
+
POINTS_PER_SERVER = 160 # this is the default in libmemcached
|
|
9
|
+
|
|
10
|
+
attr_reader :ring, :sorted_keys, :replicas, :nodes
|
|
11
|
+
|
|
12
|
+
# nodes is a list of objects that have a proper to_s representation.
|
|
13
|
+
# replicas indicates how many virtual points should be used pr. node,
|
|
14
|
+
# replicas are required to improve the distribution.
|
|
15
|
+
def initialize(nodes = [], replicas = POINTS_PER_SERVER)
|
|
16
|
+
@replicas = replicas
|
|
17
|
+
@ring = {}
|
|
18
|
+
@nodes = []
|
|
19
|
+
@sorted_keys = []
|
|
20
|
+
nodes.each do |node|
|
|
21
|
+
add_node(node)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Adds a `node` to the hash ring (including a number of replicas).
|
|
26
|
+
def add_node(node)
|
|
27
|
+
@nodes << node
|
|
28
|
+
@replicas.times do |i|
|
|
29
|
+
key = server_hash_for("#{node.id}:#{i}")
|
|
30
|
+
@ring[key] = node
|
|
31
|
+
@sorted_keys << key
|
|
32
|
+
end
|
|
33
|
+
@sorted_keys.sort!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def remove_node(node)
|
|
37
|
+
@nodes.reject! { |n| n.id == node.id }
|
|
38
|
+
@replicas.times do |i|
|
|
39
|
+
key = server_hash_for("#{node.id}:#{i}")
|
|
40
|
+
@ring.delete(key)
|
|
41
|
+
@sorted_keys.reject! { |k| k == key }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# get the node in the hash ring for this key
|
|
46
|
+
def get_node(key)
|
|
47
|
+
hash = hash_for(key)
|
|
48
|
+
idx = binary_search(@sorted_keys, hash)
|
|
49
|
+
@ring[@sorted_keys[idx]]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def iter_nodes(key)
|
|
53
|
+
return [nil, nil] if @ring.empty?
|
|
54
|
+
|
|
55
|
+
crc = hash_for(key)
|
|
56
|
+
pos = binary_search(@sorted_keys, crc)
|
|
57
|
+
@ring.size.times do |n|
|
|
58
|
+
yield @ring[@sorted_keys[(pos + n) % @ring.size]]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def hash_for(key)
|
|
65
|
+
Zlib.crc32(key)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def server_hash_for(key)
|
|
69
|
+
Digest::MD5.digest(key).unpack1("L>")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Find the closest index in HashRing with value <= the given value
|
|
73
|
+
def binary_search(ary, value)
|
|
74
|
+
upper = ary.size
|
|
75
|
+
lower = 0
|
|
76
|
+
|
|
77
|
+
while lower < upper
|
|
78
|
+
mid = (lower + upper) / 2
|
|
79
|
+
if ary[mid] > value
|
|
80
|
+
upper = mid
|
|
81
|
+
else
|
|
82
|
+
lower = mid + 1
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
upper - 1
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "delegate"
|
|
4
|
+
|
|
5
|
+
class Redis
|
|
6
|
+
class PipelinedConnection
|
|
7
|
+
attr_accessor :db
|
|
8
|
+
|
|
9
|
+
def initialize(pipeline, futures = [], exception: true)
|
|
10
|
+
@pipeline = pipeline
|
|
11
|
+
@futures = futures
|
|
12
|
+
@exception = exception
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
include Commands
|
|
16
|
+
|
|
17
|
+
def pipelined
|
|
18
|
+
yield self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def multi
|
|
22
|
+
transaction = MultiConnection.new(@pipeline, @futures)
|
|
23
|
+
send_command([:multi])
|
|
24
|
+
size = @futures.size
|
|
25
|
+
yield transaction
|
|
26
|
+
multi_future = MultiFuture.new(@futures[size..-1])
|
|
27
|
+
@pipeline.call_v([:exec]) do |result|
|
|
28
|
+
multi_future._set(result)
|
|
29
|
+
end
|
|
30
|
+
@futures << multi_future
|
|
31
|
+
multi_future
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def synchronize
|
|
37
|
+
yield self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def send_command(command, &block)
|
|
41
|
+
future = Future.new(command, block, @exception)
|
|
42
|
+
@pipeline.call_v(command) do |result|
|
|
43
|
+
future._set(result)
|
|
44
|
+
end
|
|
45
|
+
@futures << future
|
|
46
|
+
future
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def send_blocking_command(command, timeout, &block)
|
|
50
|
+
future = Future.new(command, block, @exception)
|
|
51
|
+
@pipeline.blocking_call_v(timeout, command) do |result|
|
|
52
|
+
future._set(result)
|
|
53
|
+
end
|
|
54
|
+
@futures << future
|
|
55
|
+
future
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class MultiConnection < PipelinedConnection
|
|
60
|
+
def multi
|
|
61
|
+
raise Redis::BaseError, "Can't nest multi transaction"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# Blocking commands inside transaction behave like non-blocking.
|
|
67
|
+
# It shouldn't be done though.
|
|
68
|
+
# https://redis.io/commands/blpop/#blpop-inside-a-multi--exec-transaction
|
|
69
|
+
def send_blocking_command(command, _timeout, &block)
|
|
70
|
+
send_command(command, &block)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class FutureNotReady < RuntimeError
|
|
75
|
+
def initialize
|
|
76
|
+
super("Value will be available once the pipeline executes.")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class Future < BasicObject
|
|
81
|
+
FutureNotReady = ::Redis::FutureNotReady.new
|
|
82
|
+
|
|
83
|
+
def initialize(command, coerce, exception)
|
|
84
|
+
@command = command
|
|
85
|
+
@object = FutureNotReady
|
|
86
|
+
@coerce = coerce
|
|
87
|
+
@exception = exception
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def inspect
|
|
91
|
+
"<Redis::Future #{@command.inspect}>"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def _set(object)
|
|
95
|
+
@object = @coerce ? @coerce.call(object) : object
|
|
96
|
+
value
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def value
|
|
100
|
+
::Kernel.raise(@object) if @exception && @object.is_a?(::StandardError)
|
|
101
|
+
@object
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def is_a?(other)
|
|
105
|
+
self.class.ancestors.include?(other)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def class
|
|
109
|
+
Future
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class MultiFuture < Future
|
|
114
|
+
def initialize(futures)
|
|
115
|
+
@futures = futures
|
|
116
|
+
@command = [:exec]
|
|
117
|
+
@object = FutureNotReady
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def _set(replies)
|
|
121
|
+
@object = if replies
|
|
122
|
+
@futures.map.with_index do |future, index|
|
|
123
|
+
future._set(replies[index])
|
|
124
|
+
future.value
|
|
125
|
+
end
|
|
126
|
+
else
|
|
127
|
+
replies
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Redis
|
|
4
|
+
class SubscribedClient
|
|
5
|
+
def initialize(client)
|
|
6
|
+
@client = client
|
|
7
|
+
@write_monitor = Monitor.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call_v(command)
|
|
11
|
+
@write_monitor.synchronize do
|
|
12
|
+
@client.call_v(command)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def subscribe(*channels, &block)
|
|
17
|
+
subscription("subscribe", "unsubscribe", channels, block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def subscribe_with_timeout(timeout, *channels, &block)
|
|
21
|
+
subscription("subscribe", "unsubscribe", channels, block, timeout)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def psubscribe(*channels, &block)
|
|
25
|
+
subscription("psubscribe", "punsubscribe", channels, block)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def psubscribe_with_timeout(timeout, *channels, &block)
|
|
29
|
+
subscription("psubscribe", "punsubscribe", channels, block, timeout)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ssubscribe(*channels, &block)
|
|
33
|
+
subscription("ssubscribe", "sunsubscribe", channels, block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ssubscribe_with_timeout(timeout, *channels, &block)
|
|
37
|
+
subscription("ssubscribe", "sunsubscribe", channels, block, timeout)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def unsubscribe(*channels)
|
|
41
|
+
call_v([:unsubscribe, *channels])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def punsubscribe(*channels)
|
|
45
|
+
call_v([:punsubscribe, *channels])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def sunsubscribe(*channels)
|
|
49
|
+
call_v([:sunsubscribe, *channels])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def close
|
|
53
|
+
@client.close
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
protected
|
|
57
|
+
|
|
58
|
+
def subscription(start, stop, channels, block, timeout = 0)
|
|
59
|
+
sub = Subscription.new(&block)
|
|
60
|
+
|
|
61
|
+
case start
|
|
62
|
+
when "ssubscribe" then channels.each { |c| call_v([start, c]) } # avoid cross-slot keys
|
|
63
|
+
else call_v([start, *channels])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
while event = @client.next_event(timeout)
|
|
67
|
+
if event.is_a?(::RedisClient::CommandError)
|
|
68
|
+
raise Client::ERROR_MAPPING.fetch(event.class), event.message
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
type, *rest = event
|
|
72
|
+
if callback = sub.callbacks[type]
|
|
73
|
+
callback.call(*rest)
|
|
74
|
+
end
|
|
75
|
+
break if type == stop && rest.last == 0
|
|
76
|
+
end
|
|
77
|
+
# No need to unsubscribe here. The real client closes the connection
|
|
78
|
+
# whenever an exception is raised (see #ensure_connected).
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class Subscription
|
|
83
|
+
attr :callbacks
|
|
84
|
+
|
|
85
|
+
def initialize
|
|
86
|
+
@callbacks = {}
|
|
87
|
+
yield(self)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def subscribe(&block)
|
|
91
|
+
@callbacks["subscribe"] = block
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def unsubscribe(&block)
|
|
95
|
+
@callbacks["unsubscribe"] = block
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def message(&block)
|
|
99
|
+
@callbacks["message"] = block
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def psubscribe(&block)
|
|
103
|
+
@callbacks["psubscribe"] = block
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def punsubscribe(&block)
|
|
107
|
+
@callbacks["punsubscribe"] = block
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def pmessage(&block)
|
|
111
|
+
@callbacks["pmessage"] = block
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def ssubscribe(&block)
|
|
115
|
+
@callbacks["ssubscribe"] = block
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def sunsubscribe(&block)
|
|
119
|
+
@callbacks["sunsubscribe"] = block
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def smessage(&block)
|
|
123
|
+
@callbacks["smessage"] = block
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|