IPC::ConcurrencyLimit::Lock::Redis - Locking via Redis
# see also: IPC::ConcurrencyLimit::Lock use IPC::ConcurrencyLimit; use Redis; my $redis = Redis->new(server => ...); my $limit = IPC::ConcurrencyLimit->new( type => 'Redis', max_procs => 1, # defaults to 1 redis_conn => $redis, key_name => "mylock", # optional value to store. Will be prefixed with UUID (see below) # proc_info => "...", ); my $id = $limit->get_lock; if (not $id) { warn "Couldn't get lock"; exit(); } # do work
This module requires a Redis server that supports Lua scripting.
This locking strategy uses Redis to implement an IPC::ConcurrencyLimit lock type. This particular Redis-based lock implementation uses a single Redis hash (a hash in a single Redis key) as storage for tracking the locks.
IPC::ConcurrencyLimit
The structure of the lock on the server is not considered an implementation detail, but part of the public interface. So long it is inspected and modified atomically, you can choose to modify it through different channels than the API of this class.
This is important because the lock is released in the lock object's destructor, so if a perl process segfaults or on network failure between the process and Redis then the lock cannot be released! More on that below.
Given a lock "mylock" with a max_procs setting of 5 (default: 1) and three out of five lock instances taken, the lock structure in Redis would look as follows:
"mylock"
max_procs
"mylock": { "1": "BINARYUUID1-some info", "2": "BINARYUUID2-some other", "3": "BINARYUUID3-yet other info" }
where BINARYUUIDX is understood to be a 128bit/16byte binary UUID whose first 60bits are a microsecond-precision timestamp in binary, from high to low significance bits. See "version 4s" UUIDs as described in Data::UUID::MT.
If subsequently lock number 2 is released, the structure becomes:
"mylock": { "1": "BINARYUUID1-some info", "3": "BINARYUUID3-yet other info" }
The next lock to be obtained would again use entry number 2. When creating a lock object, you may pass a proc_info parameter. This parameter (string) will be used as the value of the corresponding hash entry after prepending the lock's UUID (So proc_info would be "some info", etc. above). By default, proc_info is the empty string.
proc_info
"some info"
The combination of the time-ordered UUID and custom proc_info properties may be used to evict stale locks before attempting to obtain a new lock. The default behaviour of using the current time as part of the UUID allows for expiring old locks if that is good enough for your application. Using PIDs in proc_info could be used to clean out stale locks referring to the same client host, etc.
Most importantly, however, the UUID is (with on certainty bordering probability) unique so that you can use to clearly indicate whether you lost the lock if it changes from under you (cf. heartbeat).
heartbeat
Given a hash ref with options, attempts to obtain a lock in the pool. On success, returns the lock object, otherwise undef.
Required named parameters:
The maximum no. of locks (and thus usually processes) to allow at one time.
redis_conn
A Redis connection object. See Redis.
key_name
Indicates the Redis key to use for storing the lock hash.
Options:
If provided, this string will be stored in the value slot for the lock obtained together with a UUID (see above). Defaults to the empty string.
This IPC::ConcurrencyLimit::Lock subclass implements a heartbeat method that check whether the UUID and proc_info on the server is still the same as the UUID and proc_info properties of the object.
IPC::ConcurrencyLimit::Lock
Whenever called (successfully), updates the time portion of the UUID to the current time in both client and server.
Class method!
Given a Redis connection object, a key name for the lock, and a cutoff time stamp (in seconds, potentially fractional), removes all locks in the given key that are older than the provided cutoff time stamp.
This is only going to work on 64bit perls right now, sorry. Patches welcome.
Since heartbeat() updates the UUID timestamp, the cutoff refers to the most recent heartbeat, not to the original lock creation time. But that is what you usually want anyway.
IPC::ConcurrencyLimit and the abstract lock base class IPC::ConcurrencyLimit::Lock.
Redis, the Perl-Redis interface used by this module.
Redis::ScriptCache, which makes Lua-scripting with Redis a bit less work.
Data::UUID::MT, whose "version 4s" UUIDs are used here.
Steffen Mueller, smueller@cpan.org
smueller@cpan.org
(C) 2012 Steffen Mueller. All rights reserved. This code is available under the same license as Perl version 5.8.1 or higher. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
To install IPC::ConcurrencyLimit::Lock::Redis, copy and paste the appropriate command in to your terminal.
cpanm
cpanm IPC::ConcurrencyLimit::Lock::Redis
CPAN shell
perl -MCPAN -e shell install IPC::ConcurrencyLimit::Lock::Redis
For more information on module installation, please visit the detailed CPAN module installation guide.