NAME

DFA::Set::File - DFA implemented on the filesystem


SYNOPSIS

    use DFA::Set::File;
    $dfa=DFA::Set::File->new(
        Directory=>"$ENV{HOME}/Maildir",
        States=>{
            cur=>[],
            tmp=>[qw(new)],
            new=>[qw(cur)],
        }, 
        Terminal=>'cur');

    my $unique="12341234123.foo.com"
    $fd=$dfa->open_fd(">", $unique, "tmp");
    eval {
        # read $data from somewhere
        $fd->print($data);
    };
    $fd->close;
    if($@) {
        $dfa->remove($unique);
        die $@;
    }

    $dfa->transition($unique, 'new');


DESCRIPTION

DFA::Set::File is an implementation of DFA::Set that uses files and directories to make sure that transitions are atomic. This has the advantage of never being able to loose information if the program crashes unexpectedly (unless the filesystem crashes, in which case there's not much you can do).

An example of an application that uses this approche is qmail with Maildirs. New mail is crated in a 'tmp' state. Then moved to a 'new' state. After it has been looked at once, it is moved to a 'cur' state.

DFA::Set::File uses File::Spec to create pathnames. This allows it to be as portable as possible.


METHODS

All methods work as documented in DFA::Set, with a few extenstions and caveats detailed here.


new

    my $dfa=DFA::Set::File->new(..., Directory=>$dir, ...);

Each state is it's own directory. All directories are created under the one specified via the Directory parameter. All directories are created at instansiation time. If they can't be created, new will croak.


add

    $dfa->add($name, $payload, $state);

Creates a file and writes $payload to it. This means that $payload MUST be a scalar and not a reference. Serialisation is left as an excercise to the caller.


open_fd

    my $fd=$dfa->open_fd($mode, $name[, $state]);

Opens the file of the token $name and returns a IO::File object. While this breaks strict OO, it allows you to receive and save data as robustly as possible. Otherwise, you would have to save all data into memory, then use add() to write to the file. That wouldn't be as safe.

See IO::File for details.


remove

    $dfa->remove($name[, $state]);

Uses unlink to remove the token from the filesystem. Because find_state is relatively expensive, you can specify $state. However, if the token moved and you didn't know it, this method will croak.


list

    @names=$dfa->list($state);

This function returns all the tokens in a given state. This could be useful for cronjobs to get a list of tokens to process as a batch.

Uses opendir/readdir/closedir so it's relatively expensive.


transition

    $dfa->transition($name, $newstate);

Uses rename to move token $name from it's current state to $newstate. Because rename is an atomic operation on most useful systems, the token should never be lost. Barring catastrphic filesystem corruption, that is.


find_state

    my $state=$dfa->find_state($name);

Returns the state that the token $name is in.

Relatively expensive operation, however.


find_payload

    my $payload=$dfa->find_payload($name[, $state]);

Returns the payload of token $name. Because find_state is relatively expensive, you can specify $state. However, if the token moved and you didn't know it, this method will croak.


AUTHOR

Philip Gwyn <cpan at pied.nu>


SEE ALSO

DFA::Set, DFA::Set::Memory, perl(1).