NAME
    DBIx::Sequence - Perl extension for the generation of unique
    ID's in a database environnement.

SYNOPSIS
      use DBIx::Sequence;

      my $sequence = new DBIx::Sequence('my_dataset');
      my $next_id = $sequence->Next();

DESCRIPTION
    This module is intended to give easier portability to Perl
    database application by providing a database independant unique
    ID generator. This way, an application developer is not bound to
    use his database's SEQUENCE or auto_increment thus making his
    application portable on multiple database environnements.

    This module implements a simple Spin Locker mechanism and is
    garanteed to return a unique value every time it is called, even
    with concurrent processes. It uses your database for it's state
    storage with ANSI SQL92 compliant SQL.

INSTALLATION
            perl Makefile.PL
            make
            make test
            make install

    Note:

    If you decide to run extended tests for the module, you will
    have to provide the make test with a DSN (connect string) to
    your database (dbi:Driver:db;host=hostname) and a valid
    username/password combination for a privileged user.

    DBIx::Sequence uses 2 tables for it's operation, namely the
    dbix_sequence_state and the dbix_sequence_release tables. Those
    tables will be created if you run extended tests, if not you
    will need to create them yourself.

            dbix_sequence_state:
            | dataset  | varchar(50) |      
            | state_id | int(11)     |    

            dbix_sequence_release:
            | dataset     | varchar(50) |     
            | released_id | int(11)     |     

    Those table names are overloadable at your convenience, see the
    OVERLOADING section for details.

BASIC USAGE
    The basic usage of this module is to generate a unique ID to
    replace the use of your database's SEQUENCE of auto_increment
    field.

  INIT

    First, you need to create the sequence object:

            use DBIx::Sequence;
            my $sequence = new DBIx::Sequence({
                                                    db_user => 'scott',
                                                    db_pw => 'tiger',
                                                    db_dsn => 'dbi:mysql:scottdb',
                                                    });

    DBIx::Sequence can be used to manage multiple sets of ID's
    (perhaps you could have one dataset per table, or one and only
    one dataset). This permits you to handle multiple applications
    with the same sequence class. The dataset is normally simply a
    token string that represents your ID set. If the dataset does
    not exists, DBIx::Sequence will create automagically for you. No
    special steps are involved in the creation of a dataset.

    The arguments contains the database informations, db_user, db_pw
    and db_dsn and are stored in a hash reference.

    At this point, the object has pre cached all of the SQL that
    will be used to generate the spin locker race. It is normally a
    good idea to have a shared sequence object (especially) under
    mod_perl to save the prepare overhead.

  GETTING THE NEXT ID

    To get the next id, you simpy have to use the Next() method of
    your sequence while specifying the dataset you are getting the
    next id for.

            my $next_id = $sequence->Next($dataset);

  RELEASING ID'S.

    Generated ID's can be _explicitly_ released in your application.
    When an ID is released, the sequence will be able to give this
    id back to you throught the Next() method.

    This is how it is done:

            $sequence->Release($dataset, $id);

    Note:

    You must use release only when you are _CERTAIN_ that your ID is
    not used anymore and that you want it to be recycled. The Spin
    Locking mechanism will also take place on released id's to
    ensure that no two processes can get the same ID.

  PERMANENTLY REMOVING A DATASET

    To make DBIx::Sequence forget about an existing dataset, you
    need to use the Delete_Dataset() method.

            $sequence->Delete_Dataset($dataset);

    This will clear all state and existence for this dataset and
    will also clear it's released id's. Note that if your
    application still uses this dataset, it will be automatically
    recreated. (blank)

  BOOTSTRAPPING A DATASET FROM EXISTING DATA

    It is possible to sync the state of a DBIx::Sequence dataset by
    using the Bootstrap() method.

            $sequence->Bootstrap('my_dataset','my_bootstrap_table','my_primary_field');

    Bootstrap() takes 3 arguments.

    * The dataset to bootstrap
    * The table from wich you will bootstrap
    * The field in the bootstrap table that will be used to bootstrap the dataset.
    Bootstrap will then sync up the DBIx::Sequence's state with the
    maximum id of the 'my_primary_field' in 'my_bootstrap_table'.
    The bootstrap field must be a numeric field as you can suspect.
    The SQL function MAX() will be called on it during the bootstrap
    process.

    Note: The bootstrap method _can_ be used at runtime since it
    will initiate a race for updating the value thus following the
    same algorithm. It is recommended though that you use
    Bootstrap() when no other concurrent processes are requesting
    id's.

  OVERLOADING

    It is possible to create an overloaded class of DBIx::Sequence.
    This permits you to create a DBIx::Sequence that has different
    properties than the orignal one. The only thing you really have
    to overload to modify the behaviour of DBIx::Sequence are some
    constants:

    * STATE_TABLE : Defines the table used by DBIx::Sequence to store dataset's states.
    * RELEASE_TABLE : Defines the table used by DBIx::Sequence to store released id's.
    * COLUMN_PREFIX : A string to be prepended to every columns in the internal SQL statements.
    * DEFAULT_INIT_VALUE : Value used to init a dataset when it is first created.
    * ALLOW_ID_REUSE : When set to true, will allow the use of Release().
    * DEBUG_LEVEL : When set to true, will enable debugging to STDERR.
    So it is very easy to specify the behaviour of DBIx::Sequence
    that you wish to use by creating an overloaded class.

    Also, a very important method to overload is the getDbh()
    method. This is the function that returns the database handle to
    the DBIx::Sequence. Your overloaded class should redefine the
    getDbh method.

    Overloading getDbh will make your sequence class integrate more
    cleanly with your application.

    i.e.

            package MySequence;

            use DBI;
            use DBIx::Sequence;

            use vars qw(@ISA);
            @ISA = qw(DBIx::Sequence);

            use constant STATE_TABLE => 'my_state_table';
            use constant RELEASE_TABLE => 'my_release_table';
            use constant COLUMN_PREFIX => '';
            use constant DEFAULT_INIT_VALUE => '100';
            use constant ALLOW_ID_REUSE => 1;
            use constant DEBUG_LEVEL => 0;

            sub getDbh
            {
                    my $self = shift;

                    return MyApplication::MyDBModule::getDbh();
            }

            1;

    Then, your code can use this class for it's sequencing. Notice
    that since we overloaded getDbh(), we don't need to pass a
    second parameter to new().

            use MySequence;

            my $sequence = new MySequence();
            my $next_id = $sequence->Next($dataset);

TODO
    * Implement multiple locking mechanism (semaphore, spin, db locker)
    * Implement pluggable locking module support
AUTHOR
    Benoit Beausejour, <bbeausej@pobox.com>

NOTES
    This code was made possible by the help of individuals:

            Patrick "Peanut" Bradley <pbradley@burstofindifference.com>
            Philippe "Gozer" M. Chiasson <gozer@cpan.org>

    And the team of the SmartWorker Project
    <http://www.smartworker.org>

SUPPORT
    Support is available from the SmartWorker Project mailing list.
    Subscribe via http://www.smartworker.org.

    Support is also available by contacting me directly :
    <bbeausej@pobox.com>

SEE ALSO
    perl(1).

COPYRIGHT
    Copyright (c) 2000 Benoit Beausejour <bbeausej@pobox.com> All
    rights reserved. This program is free software, you can
    redistribute it and/or modify it under the same terms as Perl
    itself.

