NAME

Narada::Lock - manage project locks

VERSION

This document describes Narada::Lock version v2.3.8

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 .lock. Exclusive lock is set using flock(2) LOCK_EX on file .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 .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 .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

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

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 .lock.new which signal other scripts to not try to set shared lock while this file exists and get LOCK_EX on file .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

unlock_new();

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

Return: nothing.

unlock

unlock();

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

Return: nothing.

child_inherit_lock

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.

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).

COMPATIBILITY

Narada 1.x project use var/.lock instead of .lock.

Narada 1.x project use var/.lock.new instead of .lock.new.

SUPPORT

Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker at https://github.com/powerman/Narada/issues. You will be notified automatically of any progress on your issue.

Source Code

This is open source software. The code repository is available for public review and contribution under the terms of the license. Feel free to fork the repository and submit pull requests.

https://github.com/powerman/Narada

git clone https://github.com/powerman/Narada.git

Resources

AUTHOR

Alex Efros <powerman@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2008- by Alex Efros <powerman@cpan.org>.

This is free software, licensed under:

The MIT (X11) License