Changeset 16071 for lang/perl/Data-Valve

Show
Ignore:
Timestamp:
07/22/08 09:38:42 (5 years ago)
Author:
daisuke
Message:

implement strict interval mode

Location:
lang/perl/Data-Valve/trunk
Files:
9 modified

Legend:

Unmodified
Added
Removed
  • lang/perl/Data-Valve/trunk/Valve.xs

    r15617 r16071  
    88 
    99dv_bucket * 
    10 dv_bucket_create(double interval, unsigned long max) 
     10dv_bucket_create(double interval, unsigned long max, int strict_interval = 0) 
    1111 
    1212void 
     
    4444 
    4545dv_bucket * 
    46 dv_bucket__deserialize(SV *buf, double interval, long max) 
     46dv_bucket__deserialize(SV *buf, double interval, long max, int strict_interval = 0) 
    4747    PREINIT: 
    4848        STRLEN len; 
    4949        char *c_buf = (char *)SvPV(ST(0), len); 
    5050    CODE: 
    51         RETVAL = dv_bucket_deserialize(c_buf, len, interval, max); 
     51        RETVAL = dv_bucket_deserialize(c_buf, len, interval, max, strict_interval); 
    5252    OUTPUT: 
    5353        RETVAL 
  • lang/perl/Data-Valve/trunk/dv_bucket.c

    r15625 r16071  
    3333 
    3434dv_bucket* 
    35 dv_bucket_create(double interval, unsigned long max) 
     35dv_bucket_create(double interval, unsigned long max, int strict_interval) 
    3636{ 
    3737    dv_bucket *bucket; 
     
    4141    bucket->interval = interval * DV_1E6; 
    4242    bucket->count = 0; 
     43    bucket->strict_interval = strict_interval; 
    4344    bucket->head = NULL; 
    4445    bucket->tail = NULL; 
     
    106107     */ 
    107108    size_t expired = 0; 
     109    double dtime   = dv_bucket_timeval2double(tp); 
    108110 
    109111    while (  
    110112        bucket->head != NULL && 
    111         bucket->interval < dv_bucket_timeval2double(tp) - bucket->head->time 
     113        bucket->interval < dtime - bucket->head->time 
    112114    ) { 
    113115        dv_bucket_item *tmp = bucket->head; 
     
    125127 
    126128int 
    127 dv_bucket_is_full(dv_bucket *bucket) 
    128 { 
     129dv_bucket_is_full(dv_bucket *bucket, double dtime) 
     130{ 
     131    if (bucket->count == 0 || bucket->head == NULL) { 
     132        /* safety net */ 
     133        return 0; 
     134    } 
     135 
     136    /* if we're in strict_interval mode, then we check for the last entry 
     137     * in the list, and make sure that current time is more than  
     138     * last entry + interval 
     139     */ 
     140    if (bucket->strict_interval) { 
     141        return bucket->head->time + bucket->interval > dtime; 
     142    } 
     143 
     144    /* Otherwise, we care about how many items are in the list */ 
    129145    return bucket->max <= bucket->count; 
    130146} 
     
    149165{ 
    150166    struct timeval t; 
     167    double dtime; 
    151168 
    152169    gettimeofday(&t, &tzp_not_used); 
     
    154171    dv_bucket_expire( bucket, &t ); 
    155172 
     173    dtime = dv_bucket_timeval2double(&t); 
     174 
    156175    if ( dv_bucket_count( bucket ) == 0 ) { 
    157         dv_bucket_push( bucket, dv_bucket_timeval2double(&t) ); 
     176        dv_bucket_push( bucket, dtime ); 
    158177        return 1; 
    159178    } 
    160179 
    161     if ( dv_bucket_is_full(bucket) ) { 
     180    if ( dv_bucket_is_full(bucket, dtime) ) { 
    162181        return 0; 
    163182    } 
    164183 
    165     dv_bucket_push( bucket, dv_bucket_timeval2double(&t) ); 
     184    dv_bucket_push( bucket, dtime ); 
    166185    return 1; 
    167186} 
     
    183202 
    184203dv_bucket * 
    185 dv_bucket_deserialize(char *buf, size_t len, double interval, unsigned long max) 
    186 { 
    187     dv_bucket *bucket = dv_bucket_create(interval, max); 
     204dv_bucket_deserialize(char *buf, size_t len, double interval, unsigned long max, int strict_interval) 
     205{ 
     206    dv_bucket *bucket = dv_bucket_create(interval, max, strict_interval); 
    188207    char *end = buf + len; 
    189208 
  • lang/perl/Data-Valve/trunk/dv_bucket.h

    r15617 r16071  
    1818    unsigned long max; 
    1919    double interval; 
     20    int strict_interval; 
    2021    unsigned long count; 
    2122    dv_bucket_item *head; 
     
    2930/* Creates a new bucket */ 
    3031dv_bucket * 
    31     dv_bucket_create(double interval, unsigned long max); 
     32    dv_bucket_create(double interval, unsigned long max, int strict_interval); 
    3233 
    3334/* Frees a bucket */ 
     
    5758/* Returns true if count >= max */ 
    5859int 
    59     dv_bucket_is_full(dv_bucket *bucket); 
     60    dv_bucket_is_full(dv_bucket *bucket, double dtime); 
    6061 
    6162/* Pushes a new item on to the bucket */ 
     
    7374/* Deserialize a bucket from a string */ 
    7475dv_bucket * 
    75     dv_bucket_deserialize(char *buf, size_t len, double interval, unsigned long max); 
     76    dv_bucket_deserialize(char *buf, size_t len, double interval, unsigned long max, int strict_interval); 
    7677 
    7778/* returns the first bucket item */ 
  • lang/perl/Data-Valve/trunk/lib/Data/Valve.pm

    r15826 r16071  
    2323); 
    2424 
     25has 'strict_interval' => ( 
     26    is => 'rw', 
     27    isa => 'Bool', 
     28    required => 1, 
     29    default => 0 
     30); 
     31 
    2532has '__bucket_store' => ( 
    2633    accessor => 'bucket_store', 
    2734    is => 'rw', 
    2835    does => 'Data::Valve::BucketStore', 
     36    required => 1, 
    2937); 
    3038 
     
    3341no Moose; 
    3442 
    35 sub BUILD { 
    36     my ($self, $args) = @_; 
     43sub BUILDARGS { 
     44    my ($self, %args) = @_; 
    3745 
    38     my $store = delete $args->{bucket_store} || { module => 'Memory' }; 
     46    my $store = delete $args{bucket_store} || { module => 'Memory' }; 
    3947    if (! blessed $store) { 
    4048        my $module = $store->{module}; 
     
    4452        Class::MOP::load_class($module); 
    4553 
    46         $store = $module->new( %{ $store->{args} }, context => $self ); 
     54        $store = $module->new( %{ $store->{args} } ); 
    4755    } 
    48     $self->bucket_store($store); 
     56 
     57    if ($args{strict_interval}) { 
     58        # in strict_interval mode, max_items doesn't mean anything 
     59        $args{max_items} = 0; 
     60    } 
     61 
     62    return { %args, __bucket_store => $store }; 
     63} 
     64 
     65sub BUILD { 
     66    my $self = shift; 
     67    $self->bucket_store->context($self); 
    4968} 
    5069 
     
    90109mechanism is much simpler than Data::Throttler, and so is faster. 
    91110 
    92 It also comes with Memcached support for a distributed throttling. 
     111It also comes with Memcached support for a distributed throttling via 
     112memcached + keyedmutexd. This means that you can have multiple hosts throttling 
     113on the same "key". For example, multiple crawler instances can throttle  
     114requests against a single host safely. To enable distributed throttling, 
     115you simply need to specify a Data::Valve::BucketStore instance that supports 
     116distribution (i.e. Data::Valve::BucketStore::Memcached) or create your own 
     117instance, and pass it to the constructor: 
     118 
     119  Data::Valve->new( 
     120    ..., 
     121    bucket_store => { 
     122      module => "Memcached", # to use Data::Valve::BucketStore::Memcached 
     123      args   => { 
     124        servers => [ '127.0.0.1:11211' ] 
     125      } 
     126    } 
     127  ); 
     128 
     129Please note that for distributed throttling to work, you must specify the 
     130correct values in max_items, interval, and so forth, for each Data::Valve 
     131instance. Data::Valve will not try to automatically adjust this for you. 
     132You must coordinate it in the client side (i.e., whatever that's using 
     133Data::Valve) 
     134 
     135Since version 0.00006, Data::Valve supports "strict_interval" mode, where 
     136instead of counting the number of items over a range of time, it simply 
     137calculates the amount of time elapsed since the last logged request. 
     138 
     139To enable, specify it in the constrctor: 
     140 
     141  # This specifies that at least 5 seconds should have passed before 
     142  # the next item can go 
     143  Data::Valve->new( 
     144    interval        => 5, 
     145    strict_interval => 1,  
     146  ); 
    93147 
    94148=head1 METHODS 
     149 
     150=head2 new(%args) 
     151 
     152=over 4 
     153 
     154=item max_items 
     155 
     156In strict interval mode, does not mean anything. If NOT in strict interval 
     157mode, specifies the max number of items that can go through this throttler 
     158in the given interval. 
     159 
     160=item interval 
     161 
     162In strict interval mode, this specifies the number of seconds to wait between 
     163each request. If NOT in strict interval mode, specifies the number of seconds 
     164to span the requests, up to the value specified in max_items 
     165 
     166C<interval> may be a fractional number, denoting fractional seconds. 
     167 
     168=item strict_interval 
     169 
     170Boolean. Enable/Disable strict interval mode. Default is off. 
     171 
     172=cut 
    95173 
    96174=head2 try_push([key => $key_name]) 
  • lang/perl/Data-Valve/trunk/lib/Data/Valve/Bucket.pm

    r15629 r16071  
    66sub new { 
    77    my ($class, %args) = @_; 
    8     my $self  = bless create($args{interval}, $args{max_items}), $class; 
     8    $args{strict_interval} ||= 0; 
     9    my $self  = bless create($args{interval}, $args{max_items}, $args{strict_interval}), $class; 
    910     
    1011    return $self; 
  • lang/perl/Data-Valve/trunk/lib/Data/Valve/BucketStore.pm

    r15824 r16071  
    99    is       => 'rw', 
    1010    isa      => 'Data::Valve', 
    11     handles  => [ qw(max_items interval) ], 
     11    handles  => [ qw(max_items interval strict_interval) ], 
    1212); 
    1313 
  • lang/perl/Data-Valve/trunk/lib/Data/Valve/BucketStore/Memory.pm

    r15824 r16071  
    99    is => 'rw', 
    1010    isa => 'HashRef', 
     11    required => 1, 
     12    default => sub { +{} } 
    1113); 
    1214 
     
    1517no Moose; 
    1618 
    17 sub BUILD {  
    18     my $self = shift; 
    19     $self->store( { 
    20         __default => $self->create_bucket() 
    21     } ); 
    22 } 
    23  
    2419sub create_bucket 
    2520{ 
     
    2722    return Data::Valve::Bucket->new( 
    2823        max_items => $self->max_items, 
    29         interval  => $self->interval 
     24        interval  => $self->interval, 
     25        strict_interval => $self->strict_interval, 
    3026    ); 
    3127} 
  • lang/perl/Data-Valve/trunk/lib/Data/Valve/BucketStore/Object.pm

    r15790 r16071  
    4040        my $bucket; 
    4141        if ($bucket_source) { 
    42             $bucket = Data::Valve::Bucket->deserialize($bucket_source, $self->interval, $self->max_items); 
     42            $bucket = Data::Valve::Bucket->deserialize($bucket_source, $self->interval, $self->max_items, $self->strict_interval); 
    4343        } else { 
    4444            $bucket = Data::Valve::Bucket->new( 
    45                 interval  => $self->interval, 
    46                 max_items => $self->max_items, 
     45                interval        => $self->interval, 
     46                max_items       => $self->max_items, 
     47                strict_interval => $self->strict_interval 
    4748            ); 
    4849        } 
  • lang/perl/Data-Valve/trunk/t/01_basic.t

    r15595 r16071  
    11use strict; 
    2 use Test::More (tests => 16); 
     2use Test::More (tests => 20); 
    33 
    44BEGIN 
     
    4545    ok( $valve->try_push(key => "foo"), "try after 3 seconds should work"); 
    4646} 
     47 
     48{ 
     49    my $valve = Data::Valve->new( 
     50        max_items => 5, 
     51        interval  => 3, 
     52        strict_interval => 1, 
     53    ); 
     54 
     55    ok(  $valve->try_push(key => "foo"), "try 1 should succeed" ); 
     56    ok(! $valve->try_push(key => "foo"), "try 2 should fail" ); 
     57    diag("sleeping for 3 seconds..."); 
     58    sleep 3; 
     59    ok(  $valve->try_push(key => "foo"), "try 3 should succeed" ); 
     60    ok(! $valve->try_push(key => "foo"), "try 4 should fail" ); 
     61}