Skip to content

Latest commit

 

History

History
96 lines (63 loc) · 2.81 KB

FileIO.pod

File metadata and controls

96 lines (63 loc) · 2.81 KB

NAME

RevBank::FileIO - Line-based text file manipulation with advisory locking

SYNOPSIS

with_lock {
        ...
};

my $data  = slurp $filename;
my @lines = slurp $filename;
spurt $filename, @data;
append $filename, @data;

rewrite $filename, sub($line) {
        return $line;  # return changed or unchanged line
        return undef;  # exclude line from file
};

DESCRIPTION

This package implements very simple locking to protect against filesystem based race conditions when running multiple instances of revbank on the same data files.

These race conditions are probably exceptionally rare and very hard to trigger in real-world conditions, because file system access is very fast due to caching and buffering by the kernel. RevBank was used for over a decade without any known problem due such a race condition, before locking was finally added.

No attempt was made to optimize for performance, and all locks are global and exclusive.

Will wait for the global lock for as long as it takes, printing a message every few seconds to keep the user informed.

Functions

with_lock BLOCK

Gets the lock, executes the block, releases the lock again. Returns whatever the block returned.

Use this instead of get_lock to prevent forgetting to release the lock.

get_lock

Acquires the lock if it is not already held. Keeps extra virtual locks (by virtue of a simple counter) if the global lock is already held by the current process.

Calling this function directly is discouraged. Use with_lock instead.

release_lock

Decreases the number of virtual locks, releasing the real lock if none are left.

Calling this function directly is discouraged. Use with_lock instead.

slurp($filename)

Returns the entire contents of the file. In list context, returns a list of lines (including the line ending).

spurt($filename, @data)

append($filename, @data)

Writes to a file. No separators or delimiters are added to the provided data, so in general you will want to pass either the entire contents as a single string, or a list of lines that already have line endings.

rewrite($filename, sub($line) { ...; return $line; })

Rewrites the existing text file. The provided subroutine is called for each line, and must return everything that should be written back. The sub can return undef to essentially skip (remove) a line.

CAVEATS

  • A lock file is used, so external processes should not depend on the individual files being flocked.

  • Using a text editor while revbank is running and changing files will still mess things up.

  • The locking mechanism provides a lock per process; different parts (e.g. plugins) of the same process can still simultaneously do things, so keep to the pattern of always closing files before returning control or forking.