Show
Ignore:
Timestamp:
05/27/09 16:12:51 (5 years ago)
Author:
fujiwara
Message:

id generator を変更

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lang/perl/DBIx-CouchLike/trunk/lib/DBIx/CouchLike/IdGenerator.pm

    r30115 r33620  
    11package DBIx::CouchLike::IdGenerator; 
     2# original code from Data::YUID::Generator 
     3 
    24use strict; 
    35use warnings; 
    4 use Digest::SHA qw/ sha1_hex /; 
    5 use base qw/ Class::Accessor::Fast /; 
     6use Math::BigInt try => 'GMP'; 
     7 
     8no warnings qw(deprecated); # for fields 
     9 
     10use vars qw{$VERSION}; 
     11$VERSION = "0.02"; 
     12 
     13use fields qw(host_id start_time current_time min_id max_id ids); 
     14 
     15use constant EPOCH_OFFSET => 946684800; # Sat, Jan 1 2000 00:00 GMT 
     16 
     17use constant HOST_ID_BITS => 16; 
     18use constant TIME_BITS => 36; 
     19use constant SERIAL_BITS => 64 - HOST_ID_BITS - TIME_BITS; 
     20 
     21use constant TIME_SHIFT => HOST_ID_BITS + SERIAL_BITS; 
     22use constant SERIAL_SHIFT => HOST_ID_BITS; 
     23 
     24use constant SERIAL_INCREMENT => Math::BigInt->new(1) << SERIAL_SHIFT; 
     25 
     26use constant HOST_ID_MAX => (Math::BigInt->new(1) << HOST_ID_BITS) - 1; 
     27use constant TIME_MAX => (Math::BigInt->new(1) << TIME_BITS) - 1; 
     28use constant TIME_MAX_SHIFTED => TIME_MAX << TIME_SHIFT; 
     29use constant SERIAL_MAX => (Math::BigInt->new(1) << SERIAL_BITS) - 1; 
     30use constant SERIAL_MAX_SHIFTED => SERIAL_MAX << SERIAL_SHIFT; 
     31 
     32 
     33sub new { 
     34    my $self = shift; 
     35    $self = fields::new( $self ) unless ref $self; 
     36 
     37    my $host_id = shift; 
     38    if( !$host_id ) { 
     39        $host_id = int( rand( HOST_ID_MAX ) ); 
     40    } elsif( $host_id < 0 || $host_id > HOST_ID_MAX ) { 
     41        warn __PACKAGE__ . ": host ID $host_id is not in range of [0," . HOST_ID_MAX . "]\n"; 
     42        return; 
     43    } 
     44 
     45    $self->{ host_id } = $host_id; 
     46    $self->{ start_time } = time; 
     47    $self->{ current_time } = 0; 
     48    $self->{ ids } = {}; 
     49    $self->_sync(); 
     50 
     51    return $self; 
     52} 
     53 
     54 
     55sub _sync { 
     56    my $self = shift; 
     57    my $time = time; 
     58    return if( $self->{ current_time } == $time ); # FIXME: check for clock skew 
     59    $self->{ current_time } = $time; 
     60    $self->{ min_id } = $self->_make_id( 0 ) unless( $self->{ min_id } ); 
     61    $self->{ max_id } = $self->_make_id( SERIAL_MAX ); 
     62} 
     63 
     64 
     65sub _make_id { 
     66    my $self = shift; 
     67    my $serial = shift || 0; 
     68    return 
     69        ((Math::BigInt->new( $self->{ current_time } - EPOCH_OFFSET )) << TIME_SHIFT) 
     70            | (Math::BigInt->new($serial) << SERIAL_SHIFT) | $self->{ host_id }; 
     71} 
     72 
    673 
    774sub get_id { 
    875    my $self = shift; 
    9     return sha1_hex( time() . rand() ); 
     76    my $key = shift || "_"; 
     77    $self->_sync(); 
     78 
     79    if( !exists $self->{ ids }->{ $key } ) { 
     80        $self->{ ids }->{ $key } = $self->{ min_id }; 
     81        return $self->{ ids }->{ $key }; 
     82    } 
     83 
     84    return if( $self->{ ids }->{ $key } >= $self->{ max_id } ); 
     85 
     86    $self->{ ids }->{ $key } += SERIAL_INCREMENT; 
     87    return $self->{ ids }->{ $key }; 
    1088} 
    1189 
     90 
    12911;