IPC::SRLock - Set/reset locking semantics to single thread processes


IPC-SRLock documentation Contained in the IPC-SRLock distribution.

Index


Code Index:

Name

Top

IPC::SRLock - Set/reset locking semantics to single thread processes

Version

Top

0.6.$Revision: 174 $

Synopsis

Top

   use IPC::SRLock;

   my $config   = { tempdir => q(path_to_tmp_directory), type => q(fcntl) };

   my $lock_obj = IPC::SRLock->new( $config );

   $lock_obj->set( k => q(some_resource_identfier) );

   # This critical region of code is guaranteed to be single threaded

   $lock_obj->reset( k => q(some_resource_identfier) );

Description

Top

Provides set/reset locking methods which will force a critical region of code to run single threaded

Configuration and Environment

Top

This class defines accessors and mutators for these attributes:

debug

Turns on debug output. Defaults to 0

log

If set to a log object, it's debug method is called if debugging is turned on. Defaults to Class::Null

name

Used as the lock file names. Defaults to ipc_srlock

nap_time

How long to wait between polls of the lock table. Defaults to 0.5 seconds

patience

Time in seconds to wait for a lock before giving up. If set to 0 waits forever. Defaults to 0

pid

The process id doing the locking. Defaults to this processes id

time_out

Time in seconds before a lock is deemed to have expired. Defaults to 300

type

Determines which factory subclass is loaded. Defaults to fcntl

Subroutines/Methods

Top

new

This constructor implements the singleton pattern, ensures that the factory subclass is loaded in initialises it

catch

Expose the catch method in IPC::SRLock::ExceptionClass

get_table

   my $data = $lock_obj->get_table;

Returns a hash ref that contains the current lock table contents. The keys/values in the hash are suitable for passing to HTML::FormWidgets

list

   my $array_ref = $lock_obj->list;

Returns an array of hash refs that represent the current lock table

reset

   $lock_obj->reset( k => q(some_resource_key) );

Resets the lock referenced by the k attribute.

set

   $lock_obj->set( k => q(some_resource_key) );

Sets the specified lock. Attributes are:

k

Unique key to identify the lock. Mandatory no default

p

Explicitly set the process id associated with the lock. Defaults to the current process id

t

Set the time to live for this lock. Defaults to five minutes. Setting it to zero makes the lock last indefinitely

throw

Expose the throw method in IPC::SRLock::ExceptionClass

timeout_error

Return the text of the the timeout message

_arg_list

   my $args = $self->_arg_list( @rest );

Returns a hash ref containing the passed parameter list. Enables methods to be called with either a list or a hash ref as it's input parameters

_ensure_class_loaded

   $self->_ensure_class_loaded( $some_class );

Require the requested class, throw an error if it doesn't load

__hash_merge

   my $hash = __hash_merge( { key1 => val1 }, { key2 => val2 } );

Simplistic merging of two hashes

_init

Called by the constructor. Optionally overridden in the factory subclass. This allows subclass specific initialisation

_list

Should be overridden in the factory subclass

_reset

Should be overridden in the factory subclass

_set

Should be overridden in the factory subclass

Diagnostics

Top

Setting debug to true will cause the set methods to log the lock record at the debug level

Dependencies

Top

Class::Accessor::Fast
Class::MOP
Class::Null
Date::Format
IPC::SRLock::ExceptionClass
Time::Elapsed

Incompatibilities

Top

The sysv subclass will not work on cygwin

Bugs and Limitations

Top

Testing of the memcached subclass is skipped on all platforms as it requires memcached to be listening on the localhost's default memcached port localhost:11211

There are no known bugs in this module. Please report problems to the address below. Patches are welcome

Author

Top

Peter Flanigan, <Support at RoxSoft.co.uk>

License and Copyright

Top


IPC-SRLock documentation Contained in the IPC-SRLock distribution.

# @(#)$Id: SRLock.pm 174 2011-04-12 19:20:03Z pjf $

package IPC::SRLock;

use strict;
use warnings;
use version; our $VERSION = qv( sprintf '0.6.%d', q$Rev: 174 $ =~ /\d+/gmx );
use parent qw(Class::Accessor::Fast);

use Class::MOP;
use Class::Null;
use Date::Format;
use English qw(-no_match_vars);
use IPC::SRLock::Exception;
use Time::Elapsed qw(elapsed);
use Try::Tiny;

my %ATTRS = ( debug    => 0,
              log      => undef,
              name     => (lc join q(_), split m{ :: }mx, __PACKAGE__),
              nap_time => 0.1,
              patience => 0,
              pid      => undef,
              time_out => 300,
              type     => q(fcntl), );

__PACKAGE__->mk_accessors( keys %ATTRS );

sub new {
   my ($self, @rest) = @_;

   my $args  = $self->_arg_list( @rest );
   my $attrs = __hash_merge( \%ATTRS, $args );
   my $class = __PACKAGE__.q(::).(ucfirst $attrs->{type});

   $self->_ensure_class_loaded( $class ); # Load factory subclass

   my $new = bless $attrs, $class;

   $new->log  ( $new->log || Class::Null->new() );
   $new->pid  ( $PID );
   $new->_init( $args ); # Initialise factory subclass
   return $new;
}

sub get_table {
   my $self  = shift;
   my $count = 0;
   my $data  = { align  => { id    => 'left',
                             pid   => 'right',
                             stime => 'right',
                             tleft => 'right'},
                 count  => $count,
                 flds   => [ qw(id pid stime tleft) ],
                 hclass => { id => q(most) },
                 labels => { id    => 'Key',
                             pid   => 'PID',
                             stime => 'Lock Time',
                             tleft => 'Time Left' },
                 values => [] };

   for my $lock (@{ $self->list }) {
      my $flds = {};

      $flds->{id   } = $lock->{key};
      $flds->{pid  } = $lock->{pid};
      $flds->{stime} = time2str( q(%Y-%m-%d %H:%M:%S), $lock->{stime} );

      my $tleft = $lock->{stime} + $lock->{timeout} - time;

      $flds->{tleft} = $tleft > 0 ? elapsed( $tleft ) : 'Expired';
      $flds->{class}->{tleft}
                     = $tleft < 1 ? q(error dataValue) : q(odd dataValue);
      push @{ $data->{values} }, $flds;
      $count++;
   }

   $data->{count} = $count;
   return $data;
}

sub list {
   my $self = shift; return $self->_list;
}

sub reset {
   my ($self, @rest) = @_; my $args = $self->_arg_list( @rest );

   my $key = $args->{k} or $self->throw( 'No key specified' );

   return $self->_reset( q().$key );
}

sub set {
   my ($self, @rest) = @_; my $args = $self->_arg_list( @rest );

   my $key = $args->{k} or $self->throw( 'No key specified' );
   my $pid = $args->{p} || $self->pid or $self->throw( 'No pid specified' );

   return $self->_set( q().$key, $pid, $args->{t} || $self->time_out );
}

sub throw {
   my ($self, @rest) = @_; return IPC::SRLock::Exception->throw( @rest );
}

sub timeout_error {
   my ($self, $key, $pid, $when, $after) = @_; my $text;

   $text  = 'Timed out '.$key.' set by '.$pid;
   $text .= ' on '.time2str( q(%Y-%m-%d at %H:%M), $when );
   $text .= ' after '.$after.' seconds'."\n";
   return $text;
}

# Private methods

sub _arg_list {
   my ($self, @rest) = @_; $rest[ 0 ] or return {};

   return ref $rest[ 0 ] ? $rest[ 0 ] : { @rest };
}

sub _ensure_class_loaded {
   my ($self, $class, $opts) = @_; $opts ||= {};

   my $package_defined = sub { Class::MOP::is_class_loaded( $class ) };

   not $opts->{ignore_loaded} and $package_defined->() and return 1;

   try   { Class::MOP::load_class( $class ) }
   catch { $self->throw( $_ ) };

   $package_defined->() and return 1;

   my $e = 'Class [_1] loaded but package undefined';

   $self->throw( error => $e, args => [ $class ] );
   return; # Never reached
}

sub _init {
   return;
}

sub _list {
   my $self = shift;

   $self->throw( error => 'Method [_1] not overridden in [_2]',
                 args  => [ q(_list), ref $self || $self ] );
   return;
}

sub _reset {
   my $self = shift;

   $self->throw( error => 'Method [_1] not overridden in [_2]',
                 args  => [ q(_reset), ref $self || $self ] );
   return;
}

sub _set {
   my $self = shift;

   $self->throw( error => 'Method [_1] not overridden in [_2]',
                 args  => [ q(_set), ref $self || $self ] );
   return;
}

# Private subroutines

sub __hash_merge {
   return { %{ $_[ 0 ] }, %{ $_[ 1 ] || {} } };
}

1;

__END__

# Local Variables:
# mode: perl
# tab-width: 3
# End: