line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mojo::Redis2; |
2
|
34
|
|
|
34
|
|
3368171
|
use Mojo::Base 'Mojo::EventEmitter'; |
|
34
|
|
|
|
|
101069
|
|
|
34
|
|
|
|
|
148
|
|
3
|
|
|
|
|
|
|
|
4
|
34
|
|
|
34
|
|
45196
|
use Mojo::IOLoop; |
|
34
|
|
|
|
|
2880189
|
|
|
34
|
|
|
|
|
244
|
|
5
|
34
|
|
|
34
|
|
13230
|
use Mojo::Redis2::Cursor; |
|
34
|
|
|
|
|
74
|
|
|
34
|
|
|
|
|
211
|
|
6
|
34
|
|
|
34
|
|
10061
|
use Mojo::Redis2::Server; |
|
34
|
|
|
|
|
76
|
|
|
34
|
|
|
|
|
207
|
|
7
|
34
|
|
|
34
|
|
13538
|
use Mojo::URL; |
|
34
|
|
|
|
|
186321
|
|
|
34
|
|
|
|
|
218
|
|
8
|
34
|
|
|
34
|
|
1013
|
use Mojo::Util; |
|
34
|
|
|
|
|
62
|
|
|
34
|
|
|
|
|
871
|
|
9
|
34
|
|
|
34
|
|
152
|
use Carp (); |
|
34
|
|
|
|
|
116
|
|
|
34
|
|
|
|
|
770
|
|
10
|
34
|
|
50
|
34
|
|
144
|
use constant DEBUG => $ENV{MOJO_REDIS_DEBUG} || 0; |
|
34
|
|
|
|
|
56
|
|
|
34
|
|
|
|
|
2076
|
|
11
|
34
|
|
|
34
|
|
148
|
use constant DEFAULT_PORT => 6379; |
|
34
|
|
|
|
|
57
|
|
|
34
|
|
|
|
|
94628
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '0.34'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $PROTOCOL_CLASS = do { |
16
|
|
|
|
|
|
|
my $class = $ENV{MOJO_REDIS_PROTOCOL} |
17
|
|
|
|
|
|
|
||= eval "require Protocol::Redis::XS; 'Protocol::Redis::XS'" || 'Protocol::Redis'; |
18
|
|
|
|
|
|
|
eval "require $class; 1" or die $@; |
19
|
|
|
|
|
|
|
$class; |
20
|
|
|
|
|
|
|
}; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has encoding => 'UTF-8'; |
23
|
|
|
|
|
|
|
has protocol_class => $PROTOCOL_CLASS; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# DEPRECATED |
26
|
|
|
|
|
|
|
has protocol => sub { |
27
|
|
|
|
|
|
|
Mojo::Util::deprecated('protocol is deprecated in favor or protocol_class'); |
28
|
|
|
|
|
|
|
$_[0]->protocol_class->new(api => 1); |
29
|
|
|
|
|
|
|
}; |
30
|
|
|
|
|
|
|
|
31
|
1892
|
|
100
|
1892
|
1
|
10064
|
sub url { $_[0]->{url} ||= Mojo::URL->new($ENV{MOJO_REDIS_URL} || 'redis://localhost:6379'); } |
|
|
|
66
|
|
|
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub new { |
34
|
1890
|
|
|
1890
|
1
|
14837
|
my $self = shift->SUPER::new(@_); |
35
|
|
|
|
|
|
|
|
36
|
1890
|
|
|
|
|
21895
|
$self->{name} = Mojo::Util::steady_time if DEBUG; |
37
|
|
|
|
|
|
|
|
38
|
1890
|
100
|
66
|
|
|
14056
|
if ($self->{url} and ref $self->{url} eq '') { |
39
|
1885
|
100
|
|
|
|
14054
|
$self->{url} = "redis://$self->{url}" unless $self->{url} =~ /^redis:/; |
40
|
1885
|
|
|
|
|
14158
|
$self->{url} = Mojo::URL->new($self->{url}); |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
1890
|
|
|
|
|
377850
|
$self; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
0
|
|
|
0
|
1
|
0
|
sub blpop { shift->_execute(blpop => BLPOP => @_); } |
47
|
0
|
|
|
0
|
1
|
0
|
sub brpop { shift->_execute(brpop => BRPOP => @_); } |
48
|
0
|
|
|
0
|
1
|
0
|
sub brpoplpush { shift->_execute(brpoplpush => BRPOPLPUSH => @_); } |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub bulk { |
51
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
52
|
0
|
|
|
|
|
0
|
require Mojo::Redis2::Bulk; |
53
|
0
|
|
|
|
|
0
|
Mojo::Redis2::Bulk->new(_redis => $self); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub client { |
57
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
58
|
0
|
|
|
|
|
0
|
require Mojo::Redis2::Client; |
59
|
0
|
|
|
|
|
0
|
Mojo::Redis2::Client->new(_redis => $self); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub backend { |
63
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
64
|
0
|
|
|
|
|
0
|
require Mojo::Redis2::Backend; |
65
|
0
|
|
|
|
|
0
|
Mojo::Redis2::Backend->new(_redis => $self); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub multi { |
69
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
70
|
0
|
|
|
|
|
0
|
my @attributes = qw( encoding protocol_class url ); |
71
|
0
|
|
|
|
|
0
|
require Mojo::Redis2::Transaction; |
72
|
0
|
|
|
|
|
0
|
Mojo::Redis2::Transaction->new(map { $_ => $self->$_ } @attributes); |
|
0
|
|
|
|
|
0
|
|
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
0
|
|
|
0
|
1
|
0
|
sub psubscribe { shift->_pubsub(PSUBSCRIBE => @_); } |
76
|
0
|
|
|
0
|
1
|
0
|
sub punsubscribe { shift->_pubsub(PUNSUBSCRIBE => @_); } |
77
|
1
|
|
|
1
|
1
|
10
|
sub subscribe { shift->_pubsub(SUBSCRIBE => @_); } |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub unsubscribe { |
80
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
81
|
0
|
0
|
|
|
|
0
|
return $self->_pubsub(UNSUBSCRIBE => @_) if ref $_[0] eq 'ARRAY'; |
82
|
0
|
|
|
|
|
0
|
return $self->SUPER::unsubscribe(@_); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
1888
|
|
|
1888
|
|
8650
|
sub DESTROY { $_[0]->{destroy} = 1; $_[0]->_cleanup; } |
|
1888
|
|
|
|
|
6263
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub _basic_operations { |
88
|
34
|
|
|
34
|
|
401
|
'append', 'bitcount', 'bitop', 'bitpos', 'decr', 'decrby', 'del', 'echo', 'eval', 'evalsha', 'exists', 'expire', |
89
|
|
|
|
|
|
|
'expireat', 'get', 'getbit', 'getrange', 'getset', 'geoadd', 'geodist', 'geohash', 'geopos', 'georadius', |
90
|
|
|
|
|
|
|
'georadiusbymember', 'hdel', 'hexists', 'hget', 'hgetall', 'hincrby', 'hincrbyfloat', 'hkeys', 'hlen', 'hmget', |
91
|
|
|
|
|
|
|
'hmset', 'hset', 'hsetnx', 'hstrlen', 'hvals', 'incr', 'incrby', 'incrbyfloat', 'keys', 'lindex', 'linsert', |
92
|
|
|
|
|
|
|
'llen', 'lpop', 'lpush', 'lpushx', 'lrange', 'lrem', 'lset', 'ltrim', 'mget', 'move', 'mset', 'msetnx', 'persist', |
93
|
|
|
|
|
|
|
'pexpire', 'pexpireat', 'pfadd', 'pfcount', 'pfmerge', 'ping', 'psetex', 'pttl', 'publish', 'randomkey', 'rename', |
94
|
|
|
|
|
|
|
'renamenx', 'rpop', 'rpoplpush', 'rpush', 'rpushx', 'sadd', 'scard', 'sdiff', 'sdiffstore', 'set', 'setbit', |
95
|
|
|
|
|
|
|
'setex', 'setnx', 'setrange', 'sinter', 'sinterstore', 'sismember', 'smembers', 'smove', 'sort', 'spop', |
96
|
|
|
|
|
|
|
'srandmember', 'srem', 'strlen', 'sunion', 'sunionstore', 'ttl', 'type', 'zadd', 'zcard', 'zcount', 'zincrby', |
97
|
|
|
|
|
|
|
'zinterstore', 'zlexcount', 'zrange', 'zrangebylex', 'zrangebyscore', 'zrank', 'zrem', 'zremrangebylex', |
98
|
|
|
|
|
|
|
'zremrangebyrank', 'zremrangebyscore', 'zrevrange', 'zrevrangebylex', 'zrevrangebyscore', 'zrevrank', 'zscore', |
99
|
|
|
|
|
|
|
'zunionstore'; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
3762
|
|
|
3762
|
|
18926
|
sub _blocking_group {'blocking'} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub _cleanup { |
105
|
1888
|
|
|
1888
|
|
3431
|
my $self = shift; |
106
|
1888
|
|
|
|
|
3716
|
my $connections = delete $self->{connections}; |
107
|
|
|
|
|
|
|
|
108
|
1888
|
|
|
|
|
3976
|
delete $self->{pid}; |
109
|
|
|
|
|
|
|
|
110
|
1888
|
|
|
|
|
5744
|
for my $c (values %$connections) { |
111
|
1883
|
50
|
|
|
|
4555
|
my $loop = $self->_loop($c->{nb}) or next; |
112
|
1883
|
100
|
|
|
|
4906
|
$loop->remove($c->{id}) if $c->{id}; |
113
|
1883
|
|
|
|
|
3337
|
$self->$_('Premature connection close', []) for grep {$_} map { $_->[0] } @{$c->{waiting}}; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
4
|
|
|
1883
|
|
|
|
|
34514
|
|
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub _connect { |
118
|
1887
|
|
|
1887
|
|
4778
|
my ($self, $c) = @_; |
119
|
1887
|
|
|
|
|
5672
|
my $url = $self->url; |
120
|
1887
|
|
|
|
|
13951
|
my $db = $url->path->[0]; |
121
|
1887
|
|
100
|
|
|
124303
|
my @userinfo = split /:/, +($url->userinfo // ''); |
122
|
|
|
|
|
|
|
|
123
|
1887
|
|
|
|
|
19669
|
Scalar::Util::weaken($self); |
124
|
1887
|
|
|
|
|
6991
|
$c->{protocol} = $self->protocol_class->new(api => 1); |
125
|
1887
|
|
|
|
|
58634
|
$c->{name} = "$self->{name}:$c->{group}:$c->{nb}" if DEBUG; |
126
|
|
|
|
|
|
|
$c->{id} = $self->_loop($c->{nb})->client( |
127
|
|
|
|
|
|
|
{address => $url->host, port => $url->port || DEFAULT_PORT}, |
128
|
|
|
|
|
|
|
sub { |
129
|
1885
|
|
|
1885
|
|
1934301
|
my ($loop, $err, $stream) = @_; |
130
|
|
|
|
|
|
|
|
131
|
1885
|
100
|
|
|
|
5784
|
if ($err) { |
132
|
1881
|
|
|
|
|
4020
|
delete $c->{id}; |
133
|
1881
|
|
|
|
|
6685
|
return $self->_error($c, $err); |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
4
|
|
|
|
|
4
|
warn "[$c->{name}] --- @{[$self->_debug_url($url, $c)]}\n" if DEBUG; |
137
|
|
|
|
|
|
|
|
138
|
4
|
|
|
|
|
10
|
$stream->timeout(0); |
139
|
4
|
0
|
|
|
|
92
|
$stream->on(close => sub { $self and $self->_error($c) }); |
|
0
|
|
|
|
|
0
|
|
140
|
4
|
0
|
|
|
|
30
|
$stream->on(error => sub { $self and $self->_error($c, $_[1]) }); |
|
0
|
|
|
|
|
0
|
|
141
|
4
|
0
|
|
|
|
25
|
$stream->on(read => sub { $self and $self->_read($c, $_[1]) }); |
|
0
|
|
|
|
|
0
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# NOTE: unshift() will cause AUTH to be sent before SELECT |
144
|
4
|
100
|
|
|
|
17
|
unshift @{$c->{queue}}, [undef, SELECT => $db] if $db; |
|
2
|
|
|
|
|
6
|
|
145
|
4
|
100
|
|
|
|
11
|
unshift @{$c->{queue}}, [undef, AUTH => $userinfo[1]] if length $userinfo[1]; |
|
1
|
|
|
|
|
3
|
|
146
|
|
|
|
|
|
|
|
147
|
4
|
|
|
|
|
6
|
$self->emit(connection => {map { $_ => $c->{$_} } qw( group id nb )}); |
|
12
|
|
|
|
|
31
|
|
148
|
4
|
|
|
|
|
36
|
$self->_dequeue($c); |
149
|
|
|
|
|
|
|
}, |
150
|
1887
|
|
100
|
|
|
6624
|
); |
151
|
|
|
|
|
|
|
|
152
|
1887
|
|
|
|
|
511468
|
$self; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub _debug_url { |
156
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
157
|
0
|
|
|
|
|
0
|
my $url = shift->clone; |
158
|
0
|
|
|
|
|
0
|
my $c = shift; |
159
|
|
|
|
|
|
|
|
160
|
0
|
0
|
|
|
|
0
|
if (my $userinfo = $url->userinfo) { |
161
|
0
|
|
|
|
|
0
|
$userinfo =~ s!:.*!:******!; |
162
|
0
|
|
|
|
|
0
|
$url->userinfo($userinfo); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
0
|
|
|
|
|
0
|
return $url->query({g => $c->{group}}); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub _dequeue { |
169
|
0
|
|
|
0
|
|
0
|
my ($self, $c) = @_; |
170
|
0
|
|
|
|
|
0
|
my $loop = $self->_loop($c->{nb}); |
171
|
0
|
0
|
|
|
|
0
|
my $stream = $loop->stream($c->{id}) or return $self; # stream is not yet connected |
172
|
0
|
|
|
|
|
0
|
my $queue = $c->{queue}; |
173
|
0
|
|
|
|
|
0
|
my $buf; |
174
|
|
|
|
|
|
|
|
175
|
0
|
0
|
|
|
|
0
|
if (!$queue->[0]) { |
176
|
0
|
|
|
|
|
0
|
return $self; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Make sure connection has not been corrupted while event loop was stopped |
180
|
0
|
0
|
0
|
|
|
0
|
if (!$loop->is_running and $stream->is_readable) { |
181
|
0
|
|
|
|
|
0
|
$stream->close; |
182
|
0
|
|
|
|
|
0
|
return $self; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
0
|
push @{$c->{waiting}}, shift @$queue; |
|
0
|
|
|
|
|
0
|
|
186
|
0
|
|
|
|
|
0
|
$buf = $self->_op_to_command($c); |
187
|
0
|
|
|
|
|
0
|
do { local $_ = $buf; s!\r\n!\\r\\n!g; warn "[$c->{name}] <<< ($_)\n" } if DEBUG; |
188
|
0
|
|
|
|
|
0
|
$stream->write($buf); |
189
|
0
|
|
|
|
|
0
|
$self; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub _error { |
193
|
1881
|
|
|
1881
|
|
4181
|
my ($self, $c, $err) = @_; |
194
|
1881
|
|
33
|
|
|
10013
|
my $waiting = $c->{waiting} || $c->{queue}; |
195
|
|
|
|
|
|
|
|
196
|
1881
|
|
|
|
|
2579
|
warn "[$c->{name}] !!! @{[$err // 'close']}\n" if DEBUG; |
197
|
|
|
|
|
|
|
|
198
|
1881
|
50
|
|
|
|
4856
|
return if $self->{destroy}; |
199
|
1881
|
50
|
|
|
|
4443
|
return $self->_requeue($c)->_connect($c) unless defined $err; |
200
|
1881
|
50
|
|
|
|
4116
|
return $self->emit(error => $err) unless @$waiting; |
201
|
1881
|
|
|
|
|
3598
|
$self->$_($err, undef) for grep {$_} map { $_->[0] } @$waiting; |
|
1881
|
|
|
|
|
6526
|
|
|
1881
|
|
|
|
|
4626
|
|
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub _execute { |
205
|
1883
|
100
|
|
1883
|
|
7796
|
my $cb = ref $_[-1] eq 'CODE' ? pop : undef; |
206
|
1883
|
|
|
|
|
5859
|
my ($self, $group, @cmd) = @_; |
207
|
|
|
|
|
|
|
|
208
|
1883
|
50
|
66
|
|
|
16417
|
$self->_cleanup unless ($self->{pid} //= $$) eq $$; # TODO: Fork safety |
209
|
|
|
|
|
|
|
|
210
|
1883
|
100
|
|
|
|
4812
|
if ($cb) { |
211
|
2
|
|
50
|
|
|
13
|
my $c = $self->{connections}{$group} ||= {nb => 1, group => $group}; |
212
|
2
|
|
|
|
|
3
|
push @{$c->{queue}}, [$cb, @cmd]; |
|
2
|
|
|
|
|
6
|
|
213
|
2
|
50
|
|
|
|
7
|
return $self->_connect($c) unless $c->{id}; |
214
|
0
|
|
|
|
|
0
|
return $self->_dequeue($c); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
else { |
217
|
1881
|
|
50
|
|
|
8468
|
my $c = $self->{connections}{$self->_blocking_group} ||= {nb => 0, group => $self->_blocking_group}; |
218
|
1881
|
|
|
|
|
4032
|
my ($err, $res); |
219
|
|
|
|
|
|
|
|
220
|
1881
|
|
|
1881
|
|
2848
|
push @{$c->{queue}}, [sub { shift->_loop(0)->stop; ($err, $res) = @_; }, @cmd]; |
|
1881
|
|
|
|
|
16164
|
|
|
1881
|
|
|
|
|
4705
|
|
|
1881
|
|
|
|
|
23613
|
|
221
|
1881
|
50
|
|
|
|
9763
|
$c->{id} ? $self->_dequeue($c) : $self->_connect($c); |
222
|
1881
|
|
|
|
|
4646
|
$self->_loop(0)->start; |
223
|
1881
|
50
|
|
|
|
199857
|
die "[@cmd] $err" if $err; |
224
|
0
|
|
|
|
|
0
|
return $res; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub _loop { |
229
|
7532
|
100
|
66
|
7532
|
|
39852
|
$_[1] ? Mojo::IOLoop->singleton : ($_[0]->{ioloop} ||= Mojo::IOLoop->new); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub _op_to_command { |
233
|
0
|
|
|
0
|
|
0
|
my ($self, $c) = @_; |
234
|
0
|
|
|
|
|
0
|
my $op = $c->{waiting}[-1]; |
235
|
0
|
|
|
|
|
0
|
my ($i, @data); |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
0
|
for my $token (@$op) { |
238
|
0
|
0
|
|
|
|
0
|
next unless $i++; |
239
|
0
|
0
|
|
|
|
0
|
$token = Mojo::Util::encode($self->encoding, $token) if $self->encoding; |
240
|
0
|
|
|
|
|
0
|
push @data, {type => '$', data => $token}; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
0
|
$c->{protocol}->encode({type => '*', data => \@data}); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub _pubsub { |
247
|
1
|
50
|
|
1
|
|
7
|
my $cb = ref $_[-1] eq 'CODE' ? pop : sub { }; |
|
|
|
|
1
|
|
|
|
248
|
1
|
|
|
|
|
3
|
my ($self, $op) = (shift, shift); |
249
|
1
|
50
|
|
|
|
3
|
my $channels = ref $_[0] eq 'ARRAY' ? shift : []; |
250
|
|
|
|
|
|
|
|
251
|
1
|
50
|
|
|
|
3
|
unless (@$channels) { |
252
|
0
|
|
|
|
|
0
|
my $method = lc $op; |
253
|
0
|
|
|
|
|
0
|
$channels = [@_]; |
254
|
0
|
|
|
|
|
0
|
Mojo::Util::deprecated("$method(\@list, ...) is DEPRECATED: Requires an array-ref as first argument."); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
1
|
|
|
|
|
3
|
$self->_execute(pubsub => $op => @$channels, $cb); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub _read { |
261
|
2
|
|
|
2
|
|
23
|
my ($self, $c, $buf) = @_; |
262
|
2
|
|
|
|
|
3
|
my $protocol = $c->{protocol}; |
263
|
2
|
|
|
|
|
2
|
my $event; |
264
|
|
|
|
|
|
|
|
265
|
2
|
|
|
|
|
2
|
do { local $_ = $buf; s!\r\n!\\r\\n!g; warn "[$c->{name}] >>> ($_)\n" } if DEBUG; |
266
|
2
|
|
|
|
|
9
|
$protocol->parse($buf); |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
MESSAGE: |
269
|
1
|
|
|
|
|
43
|
while (my $message = $protocol->get_message) { |
270
|
0
|
|
|
|
|
0
|
my $data = $self->_reencode_message($message); |
271
|
|
|
|
|
|
|
|
272
|
0
|
0
|
0
|
|
|
0
|
if (ref $data eq 'SCALAR') { |
|
|
0
|
0
|
|
|
|
|
273
|
0
|
|
0
|
|
|
0
|
my $cb = (shift @{$c->{waiting}} || [])->[0]; |
274
|
0
|
0
|
|
|
|
0
|
$self->$cb($$data, []) if $cb; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
elsif (ref $data eq 'ARRAY' and $data->[0] and $data->[0] =~ /^(p?message)$/i) { |
277
|
0
|
|
|
|
|
0
|
$event = shift @$data; |
278
|
0
|
|
|
|
|
0
|
$self->emit($event => reverse @$data); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
else { |
281
|
0
|
|
0
|
|
|
0
|
my $cb = (shift @{$c->{waiting}} || [])->[0]; |
282
|
0
|
0
|
|
|
|
0
|
$self->$cb('', $data) if $cb; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
0
|
$self->_dequeue($c); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub _reencode_message { |
290
|
0
|
|
|
0
|
|
0
|
my ($self, $message) = @_; |
291
|
0
|
|
|
|
|
0
|
my ($type, $data) = @{$message}{qw( type data )}; |
|
0
|
|
|
|
|
0
|
|
292
|
|
|
|
|
|
|
|
293
|
0
|
0
|
0
|
|
|
0
|
if ($type ne '*' and $self->encoding and $data) { |
|
|
|
0
|
|
|
|
|
294
|
0
|
|
|
|
|
0
|
$data = Encode::decode($self->encoding, $data); |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
0
|
0
|
|
|
|
0
|
if ($type eq '-') { |
|
|
0
|
|
|
|
|
|
298
|
0
|
|
|
|
|
0
|
return \$data; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
elsif ($type ne '*') { |
301
|
0
|
|
|
|
|
0
|
return $data; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
else { |
304
|
0
|
|
|
|
|
0
|
return [map { $self->_reencode_message($_); } @$data]; |
|
0
|
|
|
|
|
0
|
|
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub _requeue { |
309
|
0
|
|
|
0
|
|
0
|
my ($self, $c) = @_; |
310
|
|
|
|
|
|
|
|
311
|
0
|
0
|
|
|
|
0
|
unshift @{$c->{queue}}, grep { $_->[0] } @{delete $c->{waiting} || []}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
312
|
0
|
|
|
|
|
0
|
return $self; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
34
|
|
|
34
|
|
135
|
sub _scan_operations { qw(scan sscan hscan zscan); } |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
for my $method (__PACKAGE__->_basic_operations) { |
318
|
|
|
|
|
|
|
my $op = uc $method; |
319
|
0
|
|
|
0
|
0
|
0
|
eval "sub $method { shift->_execute(basic => $op => \@_); }; 1" or die $@; |
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
1
|
|
|
1
|
0
|
27
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
1881
|
|
|
1881
|
0
|
11744
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
for my $method (__PACKAGE__->_scan_operations) { |
323
|
|
|
|
|
|
|
my $op = uc $method; |
324
|
|
|
|
|
|
|
Mojo::Util::monkey_patch(__PACKAGE__, |
325
|
|
|
|
|
|
|
$method, |
326
|
|
|
|
|
|
|
sub { |
327
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
328
|
0
|
|
|
|
|
|
return Mojo::Redis2::Cursor->new(command => [$op => @_])->redis($self); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
); |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
1; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=encoding utf8 |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=head1 NAME |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Mojo::Redis2 - Pure-Perl non-blocking I/O Redis driver |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=head1 VERSION |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
0.34 |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head1 DESCRIPTION |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
L is a pure-Perl non-blocking I/O L |
348
|
|
|
|
|
|
|
driver for the L real-time framework. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
L has not been maintained for a while, and it has some design |
351
|
|
|
|
|
|
|
flaws that makes it hard to work with. All of this and more is taken care of in |
352
|
|
|
|
|
|
|
L. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Want to take over L? Contact me on github and I'll let you have it. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
I encourage everyone to have a look at L, and I discourage any new |
357
|
|
|
|
|
|
|
codebase from using L. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=over 2 |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=item * L |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=item * L |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=back |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=head1 SYNOPSIS |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 Blocking |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
use Mojo::Redis2; |
372
|
|
|
|
|
|
|
my $redis = Mojo::Redis2->new; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# Will die() on error. |
375
|
|
|
|
|
|
|
$res = $redis->set(foo => "42"); # $res = OK |
376
|
|
|
|
|
|
|
$res = $redis->get("foo"); # $res = 42 |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
=head2 Non-blocking |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
Mojo::IOLoop->delay( |
381
|
|
|
|
|
|
|
sub { |
382
|
|
|
|
|
|
|
my ($delay) = @_; |
383
|
|
|
|
|
|
|
$redis->ping($delay->begin)->get("foo", $delay->begin); |
384
|
|
|
|
|
|
|
}, |
385
|
|
|
|
|
|
|
sub { |
386
|
|
|
|
|
|
|
my ($delay, $ping_err, $ping, $get_err, $get) = @_; |
387
|
|
|
|
|
|
|
# On error: $ping_err and $get_err is set to a string |
388
|
|
|
|
|
|
|
# On success: $ping = "PONG", $get = "42"; |
389
|
|
|
|
|
|
|
}, |
390
|
|
|
|
|
|
|
); |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=head2 Pub/sub |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
L can L and re-use the same object to C or |
395
|
|
|
|
|
|
|
run other Redis commands, since it can keep track of multiple connections to |
396
|
|
|
|
|
|
|
the same Redis server. It will also re-use the same connection when you |
397
|
|
|
|
|
|
|
(p)subscribe multiple times. |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
$self->on(message => sub { |
400
|
|
|
|
|
|
|
my ($self, $message, $channel) = @_; |
401
|
|
|
|
|
|
|
}); |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
$self->subscribe(["some:channel"], sub { |
404
|
|
|
|
|
|
|
my ($self, $err) = @_; |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
return $self->publish("myapp:errors" => $err) if $err; |
407
|
|
|
|
|
|
|
return $self->incr("subscribed:to:some:channel"); |
408
|
|
|
|
|
|
|
}); |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=head2 Mojolicious app |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
use Mojolicious::Lite; |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
helper redis => sub { shift->stash->{redis} ||= Mojo::Redis2->new; }; |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
get '/' => sub { |
417
|
|
|
|
|
|
|
my $c = shift; |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
my $tx = $c->render_later->tx; |
420
|
|
|
|
|
|
|
$c->redis->get('some:message', sub { |
421
|
|
|
|
|
|
|
my ($redis, $err, $message) = @_; |
422
|
|
|
|
|
|
|
$c->render(json => { error => $err, message => $message }); |
423
|
|
|
|
|
|
|
undef $tx; |
424
|
|
|
|
|
|
|
}); |
425
|
|
|
|
|
|
|
}; |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
app->start; |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=head2 Error handling |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
C<$err> in this document is a string containing an error message or |
432
|
|
|
|
|
|
|
empty string on success. |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=head1 EVENTS |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head2 connection |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
$self->on(connection => sub { my ($self, $info) = @_; ... }); |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Emitted when a new connection has been established. C<$info> is a hash ref |
441
|
|
|
|
|
|
|
with: |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
{ |
444
|
|
|
|
|
|
|
group => $str, # basic, blocking, blpop, brpop, brpoplpush, publish, ... |
445
|
|
|
|
|
|
|
id => $connection_id, |
446
|
|
|
|
|
|
|
nb => $bool, # blocking/non-blocking |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Note: The structure of C<$info> is EXPERIMENTAL. |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=head2 error |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
$self->on(error => sub { my ($self, $err) = @_; ... }); |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Emitted if an error occurs that can't be associated with an operation. |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=head2 message |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
$self->on(message => sub { |
460
|
|
|
|
|
|
|
my ($self, $message, $channel) = @_; |
461
|
|
|
|
|
|
|
}); |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Emitted when a C<$message> is received on a C<$channel> after it has been |
464
|
|
|
|
|
|
|
L to. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head2 pmessage |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
$self->on(pmessage => sub { |
469
|
|
|
|
|
|
|
my ($self, $message, $channel, $pattern) = @_; |
470
|
|
|
|
|
|
|
}); |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
Emitted when a C<$message> is received on a C<$channel> matching a |
473
|
|
|
|
|
|
|
C<$pattern>, after it has been L to. |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head2 encoding |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
$str = $self->encoding; |
480
|
|
|
|
|
|
|
$self = $self->encoding('UTF-8'); |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Holds the character encoding to use for data from/to Redis. Default is |
483
|
|
|
|
|
|
|
C. Set to C to disable encoding/decoding data. Without an |
484
|
|
|
|
|
|
|
encoding set, Redis expects and returns bytes. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=head2 protocol |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
DEPRECATED! The protocol object cannot be shared in high load |
489
|
|
|
|
|
|
|
environments. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=head2 protocol_class |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
$str = $self->protocol_class; |
494
|
|
|
|
|
|
|
$self = $self->protocol_class('Protocol::Redis::XS'); |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
Holds the class name used to parse/generate Redis messages. |
497
|
|
|
|
|
|
|
Defaults to L or L. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
L need to be installed manually. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=head2 url |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
$url = $self->url; |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Holds a L object with the location to the Redis server. Default |
506
|
|
|
|
|
|
|
is C or "redis://localhost:6379". The L need to be set |
507
|
|
|
|
|
|
|
in constructor. Examples: |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
Mojo::Redis2->new(url => "redis://x:$auth_key\@$server:$port/$database_index"); |
510
|
|
|
|
|
|
|
Mojo::Redis2->new(url => "redis://10.0.0.42:6379"); |
511
|
|
|
|
|
|
|
Mojo::Redis2->new(url => "redis://10.0.0.42:6379/1"); |
512
|
|
|
|
|
|
|
Mojo::Redis2->new(url => "redis://x:s3cret\@10.0.0.42:6379/1"); |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head1 METHODS |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
In addition to the methods listed in this module, you can call these Redis |
517
|
|
|
|
|
|
|
methods on C<$self>: |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=head3 Connection |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
echo, ping |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head3 Geo |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
geoadd, geodist, geohash, geopos, georadius, |
526
|
|
|
|
|
|
|
georadiusbymember |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=head3 Hashes |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
hdel, hexists, hget, hgetall, hincrby, hincrbyfloat, |
531
|
|
|
|
|
|
|
hkeys, hlen, hmget, hmset, hset, hsetnx, hstrlen, hvals |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=head3 HyperLogLog |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
pfadd, pfcount, pfmerge |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=head3 Keys |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
del, exists, expire, expireat, keys, move, persist, |
540
|
|
|
|
|
|
|
pexpire, pexpireat, pttl, randomkey, rename, renamenx, |
541
|
|
|
|
|
|
|
sort, ttl, type |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head3 Lists |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
lindex, linsert, llen, lpop, lpush, lpushx, lrange, lrem, |
546
|
|
|
|
|
|
|
lset, ltrim, rpop, rpoplpush, rpush, rpushx |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=head3 PubSub |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
publish |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=head3 Scripting |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
eval, evalsha |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=head3 Sets |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sadd, scard, sdiff, sdiffstore, sinter, sinterstore, |
559
|
|
|
|
|
|
|
sismember, smembers, smove, spop, srandmember, srem, |
560
|
|
|
|
|
|
|
sunion, sunionstore |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head3 Sorted Sets |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
zadd, zcard, zcount, zincrby, zinterstore, zlexcount, |
565
|
|
|
|
|
|
|
zrange, zrangebylex, zrangebyscore, zrank, zrem, |
566
|
|
|
|
|
|
|
zremrangebylex, zremrangebyrank, zremrangebyscore, |
567
|
|
|
|
|
|
|
zrevrange, zrevrangebylex, zrevrangebyscore, |
568
|
|
|
|
|
|
|
zrevrank, zscore, zunionstore |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=head3 Strings |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
append, bitcount, bitop, bitpos, decr, decrby, get, |
573
|
|
|
|
|
|
|
getbit, getrange, getset, incr, incrby, incrbyfloat, |
574
|
|
|
|
|
|
|
mget, mset, msetnx, psetex, set, setbit, setex, setnx, |
575
|
|
|
|
|
|
|
setrange, strlen |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
See L for details. |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=head2 new |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
$self = Mojo::Redis2->new(...); |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
Object constructor. Makes sure L is an object. |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
=head2 blpop |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
$self = $self->blpop(@keys, $timeout, sub { my ($self, $err, $res) = @_; }); |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
This method will issue the BLPOP command on the Redis server, but in its |
591
|
|
|
|
|
|
|
own connection. This means that C<$self> can still be used to run other |
592
|
|
|
|
|
|
|
L instead of being blocking. |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Note: This method will only work in a non-blocking environment. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
See also L. |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=head2 brpop |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
$self = $self->brpop(@keys, $timeout, sub { my ($self, $err, $res) = @_; }); |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
Follows the same API as L. |
603
|
|
|
|
|
|
|
See also L. |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=head2 brpoplpush |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
$self = $self->brpoplpush($from => $to, $timeout, sub { my ($self, $err, $res) = @_; }); |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
Follows the same API as L. |
610
|
|
|
|
|
|
|
See also L. |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
=head2 bulk |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
$obj = $self->bulk; |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
Returns a L object which can be used to group Redis |
617
|
|
|
|
|
|
|
operations. |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=head2 client |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
$self->client->$method(@args); |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
Run "CLIENT" commands using L. |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=head2 backend |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
$self->backend->$method(@args); |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
Run server commands (CONFIG, INFO, SAVE, ...) using L. |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=head2 multi |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
$txn = $self->multi; |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
This method does not perform the "MULTI" Redis command, but returns a |
636
|
|
|
|
|
|
|
L object instead. |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
The L object is a subclass of L, |
639
|
|
|
|
|
|
|
which will run all the Redis commands inside a transaction. |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head2 psubscribe |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
$self = $self->psubscribe(\@patterns, sub { my ($self, $err, $res) = @_; ... }); |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
Used to subscribe to channels that match C<@patterns>. Messages arriving over a |
646
|
|
|
|
|
|
|
matching channel name will result in L events. |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
See L for details. |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=head2 punsubscribe |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
$self = $self->punsubscribe(\@patterns, sub { my ($self, $err, $res) = @_; ... }); |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
The reverse of L. |
655
|
|
|
|
|
|
|
See L for details. |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=head2 scan, hscan, sscan, zscan |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
$cur = $self->scan(0, MATCH => 'namesoace*', COUNT => 15); |
660
|
|
|
|
|
|
|
$cur = $self->hscan('hash.key', 0, MATCH => 'pref.*'); |
661
|
|
|
|
|
|
|
$cur = $self->sscan('set.key', 0); |
662
|
|
|
|
|
|
|
$cur = $self->zscan('zset.key', 0); |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
$res = $cur->next(); |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
Methods from C family will return L object to |
667
|
|
|
|
|
|
|
iterate over elements collection. |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=head2 subscribe |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
$self = $self->subscribe(\@channels, sub { my ($self, $err, $res) = @_; ... }); |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
Used to subscribe to C<@channels>. Messages arriving over a channel will |
674
|
|
|
|
|
|
|
result in L events. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
See L for details. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head2 unsubscribe |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
$self = $self->unsubscribe(\@channels, sub { my ($self, $err, $res) = @_; ... }); |
681
|
|
|
|
|
|
|
$self = $self->unsubscribe($event); |
682
|
|
|
|
|
|
|
$self = $self->unsubscribe($event, $cb); |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
The reverse of L. It will also call L |
685
|
|
|
|
|
|
|
unless the first argument is an array-ref of C<@channels>. |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
See L for details. |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
Copyright (C) 2014, Jan Henning Thorsen |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
This program is free software, you can redistribute it and/or modify it under |
694
|
|
|
|
|
|
|
the terms of the Artistic License version 2.0. |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=head1 AUTHOR |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
Andre Parker |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
Ben Tyler - C |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
Jan Henning Thorsen - C |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
Mike Magowan - C |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=cut |