Sys-Tlock

 view release on metacpan or  search on metacpan

lib/Sys/Tlock.pm  view on Meta::CPAN

# They are for making changes on tlocks atomic.
# 
# Some background info:
#     https://rcrowley.org/2010/01/06/things-unix-can-do-atomically.html

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# Helper routines.

my sub tdn( $label , $d , $m ) {
# The tlock directory name.
    return $d.$m.'.'.$label;
    };


my sub take_master( $label , $d , $m , $p ) {
# Master lock has to be taken for any operation on the lock.

    my $now = gettimeofday;

    while (1)
      { my $rv = mkdir $d.$m.'_.'.$label;
        last if $rv == 1; # second order success
        return if gettimeofday - $now > $p;
        sleep(0.05);
      };

    1;};


my sub release_master( $label , $d , $m ) {
    rmdir $d.$m.'_.'.$label;
    1;};

# --------------------------------------------------------------------------- #
# Exportable routines.

sub tlock_take( $label , $timeout , @nampar ) {
# Take the requested lock and give it the requested timeout, return token.

    return if $label !~ m/^[a-zA-Z0-9\-\_\.]+$/;
    return if $timeout <= 0;
    my $n;
    if (scalar @nampar == 1) { # For backwards compatability. Will be removed.
        $n = {patience => $nampar[0]};
        warn 'The optional patience parameter in tlock_take is deprecated. Use a named parameter instead.';
        }
    else {
        $n = {@nampar};
        };
    my $d = dir($n);
    my $m = marker($n);
    my ($o,$g) = owner($n)->@*;
    my $p = patience($n);

    take_master($label,$d,$m,$p) or return;

    my $t;
    if ( not tlock_taken($label,$n->%*) ) {
        my $tdn = tdn($label,$d,$m);
        mkdir $tdn if not -e $tdn;
        chown $o , $g , $tdn;
        mkdir $tdn.'/d' if not -e $tdn.'/d';
        chown $o , $g , $tdn.'/d';
        $t = int time;
        utime undef , $t , $tdn;
        utime undef , $timeout , $tdn.'/d';
        };

    release_master($label,$d,$m);
    $_ = $t; return $_;
    }; # sub tlock_take


sub tlock_renew( $label , $token , $timeout , %nampar ) {
# Set a new timeout, counting from now, for the given lock.
    return if $timeout <= 0;
    my $n = {%nampar};
    my $d = dir($n);
    my $m = marker($n);
    my $p = patience($n);
    take_master($label,$d,$m,$p) or return;
    utime undef , int(time) - $token + $timeout , tdn($label,$d,$m).'/d'
      if tlock_alive($label,$token,%nampar);
    release_master($label,$d,$m);
    return 1;
    };


sub tlock_release( $label , $token , %nampar ) {
# Remove the lock.
    my $n = {%nampar};
    my $d = dir($n);
    my $m = marker($n);
    my $p = patience($n);
    take_master($label,$d,$m,$p) or return;
    my $t = tlock_token($label,%nampar);
    if ($token == $t) {
        my $tdn = tdn($label,$d,$m);
        rmdir $tdn.'/d' if -e $tdn.'/d';
        rmdir $tdn      if -e $tdn;
        };
    release_master($label,$d,$m);
    return 1;
    };


sub tlock_alive( $label , $token , %nampar ) {
# True if the lock with the given token is still taken.
    my $t = tlock_token($label,%nampar);
    return if not defined $t;
    return 1 if $token == $t;
    return;
    };


sub tlock_taken( $label , %nampar ) {
# True if the lock is taken.
    return if not defined tlock_expiry($label,%nampar);
    return 1;
  };


sub tlock_expiry( $label , %nampar ) {



( run in 1.886 second using v1.01-cache-2.11-cpan-5511b514fd6 )