The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

RedisDB - Perl extension to access redis database

SYNOPSIS

    use RedisDB;

    my $redis = RedisDB->new(host => 'localhost', port => 6379);
    $redis->set($key, $value);
    my $value = $redis->get($key);

DESCRIPTION

This module provides interface to access redis key-value store. It transparently handles disconnects and forks. It supports transactions, pipelining, and subscription mode.

METHODS

$class->new(%options)

Creates the new RedisDB object. The following options are accepted:

host

domain name of the host running redis server. Default: "localhost"

port

port to connect. Default: 6379

path

you can connect to redis using UNIX socket. In this case instead of "host" and "port" you should specify path.

password

Password, if redis server requires authentication. Alternatively you can use auth method after connection.

database

DB number to use. Specified database will be selected immediately after connecting to the server. Database changes when you sending select command to the server. You can get current database using selected_database method. Default value is 0.

timeout

IO timeout. With this option set, if IO operation has taken more than specified number of seconds, module will croak. Note, that some OSes do not support SO_RCVTIMEO, and SO_SNDTIMEO socket options, in this case timeout will not work.

utf8

Assume that all data on the server encoded in UTF-8. As result all strings will be converted to UTF-8 before sending to server, and all results will be decoded from UTF-8. See "UTF-8 SUPPORT".

lazy

by default new establishes connection to the server. If this parameter is set, then connection will be established when you will send a command to the server.

$self->execute($command, @arguments)

send a command to the server and return the result. It will throw the exception if the server returns an error. It may be more convenient to use instead of this method wrapper named after the corresponding redis command. E.g.:

    $redis->execute('set', key => 'value');
    # is the same as
    $redis->set(key => 'value');

See "WRAPPER METHODS" section for the full list of defined aliases.

Note, that you can't use execute if you have sent some commands using send_command method without callback argument and have not yet got all replies.

$self->send_command($command[, @arguments][, \&callback])

send a command to the server. Returns true if the command was successfully sent, or dies if an error occured. Note, that it does not return reply from the server, you should retrieve it using the get_reply method, or if callback has been specified, it will be invoked upon receiving the reply with two arguments: the RedisDB object, and the reply from the server. If the server returns an error, the second argument to the callback will be a RedisDB::Error object, you can get description of the error using this object in string context. If you are not interested in reply, you can use RedisDB::IGNORE_REPLY constant as the last argument.

Note, that RedisDB does not run any background threads, so it will not receive the reply and invoke the callback unless you call some of its methods which check if there are replies from the server, like send_command, reply_ready, get_reply, or get_all_replies.

$self->send_command_cb($command[, @arguments][, \&callback])

send a command to the server, invoke specified callback on reply. The callback is invoked with two arguments: the RedisDB object, and reply from the server. If the server returned an error, the second argument will be a RedisDB::Error object, you can get description of the error using this object in string context. If the callback is not specified, the reply will be discarded. Note, that RedisDB does not run any background threads, so it will not receive the reply and invoke the callback unless you call some of its methods which check if there are replies from the server, like send_command, send_command_cb, reply_ready, get_reply, or get_all_replies.

DEPRECATED: this method is deprecated and may be removed in some future version. Please use send_command method instead. If you are using send_command_cb with &callback argument, you can just replace the method with send_command and it will do the same. If you are using send_command_cb with the default callback, you should add the RedisDB::IGNORE_REPLY constant as the last argument when replacing the method with send_command. Here is the example that shows equivalents with send_command:

    $redis->send_command_cb("SET", "Key", "Value");
    # may be replaced with
    $redis->send_command("SET", "Key", "Value", RedisDB::IGNORE_REPLY);

    $redis->send_command_cb("GET", "Key", \&process_reply);
    # may be replaced with
    $redis->send_command("GET", "Key", \&process_reply);

$self->reply_ready

This method may be used in the pipelining mode to check if there are some replies already received from the server. Returns the number of replies available for reading.

$self->mainloop

this method blocks till all replies from the server will be received

$self->get_reply

receive reply from the server. Method croaks if the server returns an error.

$self->get_all_replies

Wait for the replies to all the commands sent and return them as a list.

$self->replies_to_fetch

Return the number of commands sent to the server replies to which wasn't yet retrieved with get_reply or get_all_replies.

$self->selected_database

Get currently selected database.

$self->reset_connection

Resets connection. This closes existing connection and drops all previously sent requests. After invoking this method the object returns to the same state as it was returned by the constructor.

$self->version

Return the version of the server the client is connected to. The version is returned as a floating point number represented the same way as the perl versions. E.g. for redis 2.1.12 it will return 2.001012.

WRAPPER METHODS

Instead of using execute and send_command methods directly, it may be more convenient to use wrapper methods with names matching names of the redis commands. These methods call execute or send_command depending on the presence of the callback argument. If callback is specified, the method invokes send_command and returns as soon as the command has been sent to the server; when the reply is received, it will be passed to the callback (see "PIPELINING SUPPORT"). If there is no callback, the method invokes execute, waits for the reply from the server, and returns it. E.g.:

    $val = $redis->get($key);
    # equivalent to
    $val = $redis->execute("get", $key);

    $redis->get($key, sub { $val = $_[1] });
    # equivalent to
    $redis->send_command("get", $key, sub { $val = $_[1] });

The following wrapper methods are defined: append, auth, bgrewriteaof, bgsave, blpop, brpop, brpoplpush, config_get, config_set, config_resetstat, dbsize, debug_object, debug_segfault, decr, decrby, del, echo, exists, expire, expireat, flushall, flushdb, get, getbit, getrange, getset, hdel, hexists, hget, hgetall, hincrby, hkeys, hlen, hmget, hmset, hset, hsetnx, hvals, incr, incrby, keys, lastsave, lindex, linsert, llen, lpop, lpush, lpushx, lrange, lrem, lset, ltrim, mget, move, mset, msetnx, persist, ping, publish, quit, randomkey, rename, renamenx, rpop, rpoplpush, rpush, rpushx, sadd, save, scard, sdiff, sdiffstore, select, set, setbit, setex, setnx, setrange, sinter, sinterstore, sismember, slaveof, smembers, smove, sort, spop, srandmember, srem, strlen, sunion, sunionstore, sync, ttl, type, unwatch, watch, zadd, zcard, zcount, zincrby, zinterstore, zrange, zrangebyscore, zrank, zrem, zremrangebyrank, zremrangebyscore, zrevrange, zrevrangebyscore, zrevrank, zscore, zunionstore

See description of all commands in redis documentation at http://redis.io/commands.

The following commands implement some additional postprocessing of results:

$self->info

return information and statistics about the server. Redis-server returns information in form of field:value, the info method parses result and returns it as a hash reference.

$self->shutdown

Shuts the redis server down. Returns undef, as the server doesn't send the answer. Croaks in case of the error.

UTF-8 SUPPORT

The redis protocol is designed to work with the binary data, both keys and values are encoded in the same way as sequences of octets. By default this module expects all data to be just strings of bytes. There is an option to treat all data as UTF-8 strings. If you pass utf8 parameter to the constructor, module will encode all strings to UTF-8 before sending them to server, and will decode all strings received from server from UTF-8. This has following repercussions you should be aware off: first, you can't store binary data on server with this option on, it would be treated as a sequence of latin1 characters, and would be converted into a corresponding sequence of UTF-8 encoded characters; second, if data returned by the server is not a valid UTF-8 encoded string, the module will croak, and you will have to reinitialize the connection. Generally, I would recommend to write a wrapper around RedisDB instead of setting utf8 option.

ERROR HANDLING

If an error happens which the module can't handle, it will croak. It may happen as a result of a network error, or invalid data encoding, or if the server returned an error reply. In some cases the RedisDB object after throwing an exception will be left in inconsistant state. If you want to continue using the object after getting an exception, you should invoke the "reset_connection" method on it. This will drop current connection and all outstanding requests, so the object will return to the same state it was just after creation with the "new" method. If the connection was in subscription mode, you will have to restore all the subscriptions, if it was in the middle of transaction, you will have to start the transaction again.

HANDLING OF SERVER DISCONNECTS

Redis server may close a connection if it was idle for some time, also the connection may be closed in case when redis-server was restarted. RedisDB restores a connection to the server, but only if no data was lost as a result of the disconnect. E.g. if the client was idle for some time and the redis server closed the connection, it will be transparently restored on sending next command. If you sent a command and the server has closed the connection without sending a complete reply, the connection will not be restored and the module will throw an exception. Also the module will throw an exception if the connection was closed in the middle of a transaction or while you're in a subscription loop.

PIPELINING SUPPORT

You can send commands in the pipelining mode. It means you are sending multiple commands to the server without waiting for the replies. This is implemented by the send_command method. Recommended way of using it is to pass a reference to the callback function as the last argument. When module receives reply from the server, it will call this function with two arguments: reference to the RedisDB object, and reply from the server. It is important to understand though, that RedisDB does not run any background threads, neither it checks for the replies by setting some timer, so e.g. in the following example callback will never be invoked:

    my $pong;
    $redis->send_command( "ping", sub { $pong = $_[1] } );
    sleep 1 while not $pong;    # this will never return

Therefore you need perriodically trigger check for the replies. The check is triggered when you call the following methods: send_command, reply_ready, get_reply, get_all_replies. Calling wrapper method, like $redis->get('key'), will also trigger check as internally wrapper methods use methods listed above.

Also you can omit callback argument when invoke send_command. In this case you have to fetch reply later explicitly using get_reply method. This is how synchronous execute is implemented, basically it is:

    sub execute {
        my $self = shift;
        $self->send_command(@_);
        return $self->get_reply;
    }

That is why it is not allowed to call execute unless you have got replies to all commands sent previously with send_command without callback. Using send_command without callback is not recommended.

Sometimes you are not interested in replies sent by the server, e.g. SET command usually just return 'OK', in this case you can pass to send_command callback which ignores its arguments, or use RedisDB::IGNORE_REPLY constant, it is a no-op function:

    for (@keys) {
        # execute will not just send 'GET' command to the server,
        # but it will also receive response to the 'SET' command sent on
        # the previous loop iteration
        my $val = $redis->execute( "get", $_ );
        $redis->send_command( "set", $_, fun($val), RedisDB::IGNORE_REPLY );
    }
    # and this will wait for the last reply
    $redis->mainloop;

or using "WRAPPER METHODS" you can rewrite it as:

    for (@keys) {
        my $val = $redis->get($_);
        $redis->set( $_, fun($val), RedisDB::IGNORE_REPLY );
    }
    $redis->mainloop;

SUBSCRIPTIONS SUPPORT

RedisDB supports subscriptions to redis channels. In the subscription mode you can subscribe to some channels and receive all the messages sent to these channels. Every time RedisDB receives a message for the channel it invokes a callback provided by the user. User can specify different callbacks for the different channels. When in the subscription mode you can subscribe to additional channels, or unsubscribe from the channels you subscribed to, but you can't use any other redis commands like set, get, etc. Here is the example of running in the subscription mode:

    my $message_cb = sub {
        my ($redis, $channel, $pattern, $message) = @_;
        print "$channel: $message\n";
    };
    
    my $control_cb = sub {
        my ($redis, $channel, $pattern, $message) = @_;
        if ($channel eq 'control.quit') {
            $redis->unsubscribe;
            $redis->punsubscribe;
        }
        elsif ($channel eq 'control.subscribe') {
            $redis->subscribe($message);
        }
    };
    
    subscription_loop(
        subscribe => [ 'news',  ],
        psubscribe => [ 'control.*' => $control_cb ],
        default_callback => $message_cb,
    );

subscription_loop will subscribe you to the news channel and control.* channels. It will call specified callbacks every time a new message received. You can subscribe to additional channels sending their names to the control.subscribe channel. You can unsubscribe from all the channels by sending a message to the control.quit channel. Every callback receives four arguments: the RedisDB object, the channel for which the message was received, the pattern if you subscribed to this channel using psubscribe method, and the message itself.

You can publish messages into the channels using the publish method. This method should be called when you in the normal mode, and can't be used while you're in the subscription mode.

Following methods can be used in subscribtion mode:

$self->subscription_loop(%parameters)

Enter into the subscription mode. The method subscribes you to the specified channels, waits for the messages, and invokes the appropriate callback for every received message. The method returns after you unsubscribed from all the channels. It accepts the following parameters:

default_callback

reference to the default callback. This callback is invoked for a message if you didn't specify other callback for the channel this message comes from.

subscribe

an array reference. Contains the list of channels you want to subscribe. A channel name may be optionally followed by the reference to a callback function for this channel. E.g.:

    [ 'news', 'messages', 'errors' => \&error_cb, 'other' ]

channels "news", "messages", and "other" will use default callback, but for the "errors" channel error_cb function will be used.

psubscribe

same as subscribe, but you specify patterns for channels' names.

All parameters are optional, but you must subscribe at least to one channel. Also if default_callback is not specified, you have to explicitely specify a callback for every channel you are going to subscribe.

$self->subscribe($channel[, $callback])

Subscribe to the additional $channel. If $callback is not specified, default callback will be used.

$self->psubscribe($pattern[, $callback])

Subscribe to additional channels matching $pattern. If $callback is not specified, default callback will be used.

$self->unsubscribe([@channels])

Unsubscribe from the listed @channels. If no channels was specified, unsubscribe from all the channels.

$self->punsubscribe([@patterns])

Unsubscribe from the listed @patterns. If no patterns was specified, unsubscribe from all the channels to which you subscribed using psubscribe.

$self->subscribed

Return list of channels to which you have subscribed using subscribe

$self->psubscribed

Return list of channels to which you have subscribed using psubscribe

TRANSACTIONS SUPPORT

Transactions allow you to execute a sequence of commands in a single step. In order to start a transaction you should use the multi method. After you have entered a transaction all the commands you issue are queued, but not executed till you call the exec method. Tipically these commands return string "QUEUED" as result, but if there is an error in e.g. number of arguments, they may croak. When you call exec, all the queued commands will be executed and exec will return a list of results for every command in the transaction. If any command has failed, exec will croak. If instead of exec you call discard, all scheduled commands will be canceled.

You can set some keys as watched. If any whatched key has been changed by another client before you called exec, the transaction will be discarded and exec will return false value.

$self->multi

Enter the transaction. After this and till exec or discard will be called, all the commands will be queued but not executed.

$self->exec

Execute all queued commands and finish the transaction. Returns a list of results for every command. Will croak if some command has failed. Also unwatches all the keys. If some of the watched keys has been changed by other client, the transaction will be canceled and exec will return false.

$self->discard

Discard all queued commands without executing them and unwatch all keys.

SEE ALSO

Redis, Redis::hiredis, AnyEvent::Redis

WHY ANOTHER ONE

I was in need of the client for redis database. AnyEvent::Redis didn't suite me as it requires an event loop, and it didn't fit into the existing code. The problem with Redis is that it didn't (at the time I started this) reconnect to the server if connection was closed after timeout or as result of the server restart, and it does not support pipelining. After analizing what I need to change in Redis in order to get all I want, I decided that it will be simplier to write the new module from scratch. This also solves the problem of backward compatibility.

BUGS

Please report any bugs or feature requests via GitHub bug tracker at http://github.com/trinitum/RedisDB/issues.

Known bugs are:

Timeout support is OS dependent. If OS doesn't support SO_SNDTIMEO and SO_RCVTIMEO options timeouts will not work.

ACKNOWLEDGEMENTS

Sanko Robinson and FunkyMonk helped me with porting this module to Windows.

HIROSE Masaake fixed handling of commands containing space (like "CONFIG GET")

AUTHOR

Pavel Shaydo, <zwon at cpan.org>

LICENSE AND COPYRIGHT

Copyright 2011, 2012 Pavel Shaydo.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.