++ed by:

2 non-PAUSE users.

Alex Efros
and 1 contributors

NAME

Narada::Lock - manage project locks

VERSION

This document describes Narada::Lock version 1.1.0

SYNOPSIS

    use Narada::Lock qw( shared_lock unlock child_inherit_lock );
    use Narada::Lock qw( exclusive_lock unlock_new unlock );

    shared_lock();
    unlock();
    shared_lock(0) or die "can't get lock right now";
    unlock();
    shared_lock(5) or die "can't get lock in 5 seconds";
    unlock();

    shared_lock();
    system('sleep 1');
    child_inherit_lock(1);
    system('sleep 10 &');
    child_inherit_lock(0);
    system('sleep 1');
    unlock();

    exclusive_lock();
    # do critical operations, reboot-safe
    unlock_new();
    # do non-critical operations, still in exclusive mode
    unlock();

DESCRIPTION

To allow safe backup/update/maintenance of project, there should be possibility to guarantee consistent state of project, at some point. To reach this goal, ALL operations which modify project data on disk (including both project files and database) must be done under shared lock, and all operations which require consistent project state must be done under exclusive lock.

This module contain helper functions to manage project locks, but all operations required for these locks can be implemented using any programming language, so all applications in project (including non-perl applications) are able to manage project locks.

Shared lock is set using flock(2) LOCK_SH on file 'var/.lock'. Exclusive lock is set using flock(2) LOCK_EX on file 'var/.lock'.

FREEZE NEW TASKS

There exists scenario when it's impossible to set exclusive lock: if new tasks will start and set shared lock before old tasks will drop shared lock (and so shared lock will be set all of time).

To work around this scenario another file 'var/.lock.new' should be used as semaphore - it should be created before trying to set exclusive lock, and new tasks shouldn't try to set shared lock while this file exists.

This file should be removed after finishing critical operations - this guarantee project data will not change even if system will be rebooted, because after reboot existence of file 'var/.lock.new' will prevent from starting new tasks with shared locks but not prevent from placing exclusive lock again and continue these critical operations.

INTERFACE

shared_lock( $timeout )

Try to get shared lock which is required to modify any project data (files or database).

If $timeout undefined - will wait forever until lock will be granted. If $timeout >=1 will try to get lock every 1 second until $timeout expire.

Use unlock() to free this lock.

Return: true if able to get lock.

exclusive_lock()

Try to get exclusive lock which is required to guarantee consistent project state (needed while backup/update/maintenance operations).

Set two locks: create file 'var/.lock.new' which signal other scripts to not try to set shared lock while this file exists and get LOCK_EX on file 'var/.lock' to be sure all current tasks finished and unlocked their shared locks.

Will delay until get lock.

Use unlock_new() in combination with exit() or unlock() to free these locks.

Return: nothing.

unlock_new()

Free first lock set by exclusive_lock() (i.e. remove file 'var/.lock.new'). This allow other tasks to get shared_lock() after this process exit or call unlock().

Return: nothing.

unlock()

Free lock set by shared_lock() (or second lock set by exclusive_lock()).

Return: nothing.

child_inherit_lock( $is_inherit )

By default, child processes don't inherit our FD with lock. This is acceptable only if we don't run child in background or if child will get own locks on start.

In other cases you should call child_inherit_lock() with true value in $is_inherit to force child to inherit our lock (just like djb's `setlock` or Pepe's `chpst -[lL]` do). Calling child_inherit_lock() with false value in $is_inherit will switch back to default behaviour (new child will not inherit FD with lock).

Examples:

 # OK: not in background
 system("rm -rf var/something");

 # OK: in background, but this is our script,
 # which will get lock on it's own
 system("./another_script_of_this_project &");

 # ERROR: in background, no lock
 system("( sleep 5; rm -rf var/something ) &");

 # OK: in background, inherit lock
 child_inherit_lock(1); # from now all childs will inherit lock
 system("( sleep 5; rm -rf var/something ) &");
 child_inherit_lock(0); # next child will not inherit lock

Return: nothing.

DIAGNOSTICS

open: %s
flock: %s
fcntl: %s
touch: %s

Probably directory 'var/' or files 'var/.lock' and 'var/.lock.new' doesn't exists or has wrong permissions.

CONFIGURATION AND ENVIRONMENT

Narada::Lock requires configuration files and directories provided by Narada framework.

If $ENV{NARADA_SKIP_LOCK} is set to any true value then shared_lock(), exclusive_lock(), unlock_new(), unlock() and child_inherit_lock() will do nothing (shared_lock() will return true).

DEPENDENCIES

 Perl6::Export::Attrs

INCOMPATIBILITIES

None reported.

BUGS AND LIMITATIONS

No bugs have been reported.

Please report any bugs or feature requests to bug-narada@rt.cpan.org, or through the web interface at http://rt.cpan.org.

AUTHOR

Alex Efros <powerman-asdf@ya.ru>

LICENSE AND COPYRIGHT

Copyright (c) 2008-2013 Alex Efros <powerman-asdf@ya.ru>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.

DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.