CHI-Cascade

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

    Key/value pair arguments may be provided to set up the initial state.
    Options are:

    chi Required. Instance of CHI object. The CHI::Cascade doesn't construct
        this object for you. Please create instance of "CHI" yourself.

    busy_lock
        Optional. Default is *never*. *This is not "busy_lock" option of
        CHI!* This is amount of time (to see "DURATION EXPRESSIONS" in CHI)
        until all target locks expire. When a target is to being computing
        it is locked. If process which is to be computing target and it will
        die or OS will be hangs up we can dead locks and locked target will
        never recomputed again. This option helps to avoid it. You can set
        up a special busy_lock for rules too.

    target_chi
        Optional. This is CHI cache for target markers. Default value is
        value of "chi" option. It can be useful if you use a "l1_cache" in
        CHI option. So you can separate data of targets from target markers
        - data will be kept in a file cache and a marker in memory cache for
        example.

README  view on Meta::CPAN

            Optional. You can pass in your code any additional parameters by
            this option. These parameters are accessed in your rule's code
            through "params" in CHI::Cascade::Rule method of
            CHI::Cascade::Rule instance object.

        busy_lock
            Optional. Default is "busy_lock" of constructor or *never* if
            first is not defined. *This is not "busy_lock" option of CHI!*
            This is amount of time (to see "DURATION EXPRESSIONS" in CHI)
            until target lock expires. When a target is to being computed it
            is locked. If process which to be recomputing a target and it
            will die or OS will be hangs up we can dead locks and locked
            target will never recomputed again. This option helps to avoid
            it.

        recomputed
            Optional. This is a computational callback (coderef). If target
            of this rule was recomputed this callback will be executed right
            away after a recomputed value has been saved in cache. The
            callback will be executed as $coderef->( $rule, $target, $value
            ) where passed parameters are:

lib/CHI/Cascade.pm  view on Meta::CPAN

    }
    else {
        croak qq{The rule's target "$rule->{target}" is unknown type};
    }
}

sub target_computing {
    my $trg_obj;

    ( $trg_obj = $_[0]->{target_chi}->get("t:$_[1]") )
      ? ( ( ${ $_[2] } = $trg_obj->ttl ), $trg_obj->locked ? 1 : 0 )
      : 0;
}

sub target_is_actual {
    my ( $self, $target, $actual_term ) = @_;

    my $trg_obj;

    ( $trg_obj = $self->{target_chi}->get("t:$target") )
      ? $trg_obj->is_actual( $actual_term )

lib/CHI/Cascade.pm  view on Meta::CPAN

      if ($value);

    CHI::Cascade::Value->new( state => CASCADE_NO_CACHE );
}

sub target_lock {
    my ( $self, $rule ) = @_;

    my $target = $rule->target;

    # If target is already locked - a return
    return
      if ( $self->target_locked( $rule ) );

    my $trg_obj;
    $trg_obj = CHI::Cascade::Target->new
      unless ( ( $trg_obj = $self->{target_chi}->get("t:$target") ) );

    $trg_obj->lock;
    $self->{target_chi}->set( "t:$target", $trg_obj, $rule->target_expires( $trg_obj ) );

    $rule->{run_instance}{target_locks}{$target} = 1;
}

lib/CHI/Cascade.pm  view on Meta::CPAN


sub touch {
    my ( $self, $target ) = @_;

    if ( my $trg_obj = $self->{target_chi}->get("t:$target") ) {
        $trg_obj->touch;
        $self->{target_chi}->set( "t:$target", $trg_obj, $self->find( $target )->target_expires( $trg_obj ) );
    }
}

sub target_locked {
    my ( $self, $rule ) = @_;

    exists $rule->{run_instance}{target_locks}{ $rule->target };
}

sub recompute {
    my ( $self, $rule, $target, $dep_values) = @_;

    die CHI::Cascade::Value->new( state => CASCADE_DEFERRED )
      if $rule->{run_instance}{run_opts}{defer};

lib/CHI/Cascade.pm  view on Meta::CPAN


                die $exception;
            }

            return $ret;
        };

        $self->target_lock($rule)
          if ! $self->target_time($target);

        $should_be_recomputed = $self->target_locked($rule);

        if ( defined $ttl && $ttl > 0 && ! $should_be_recomputed ) {
            $ret_state = CASCADE_TTL_INVOLVED;
            $run_instance->{ttl} = $ttl;
        }
        else {
            my (
                $rule_ttl,
                $circle_hash,
                $start_time,

lib/CHI/Cascade.pm  view on Meta::CPAN

                delete $run_instance->{ $circle_hash }{$target}{$dep_target};
            }

            if ( defined $min_start_time ) {
                $ret_state = CASCADE_TTL_INVOLVED;
                $self->target_start_ttl( $rule, $min_start_time );
                $run_instance->{ttl} = $min_start_time + $rule_ttl - Time::HiRes::time;
            }
        }

        if ( $self->target_locked($rule) ) {
            # We should recompute this target
            # So we should recompute values for other dependencies
            foreach $dep_target (keys %dep_values) {
                if (   ! defined $dep_values{$dep_target}->[1]
                    || ! $dep_values{$dep_target}->[1]->is_value )
                {
                    $self->{stats}{dependencies_lookup}++;
                    $catcher->( sub {
                        if ( ! ( $dep_values{$dep_target}->[1] = $self->value_ref_if_recomputed( $dep_values{$dep_target}->[0], $dep_target, 1 ) )->is_value ) {
                            $self->target_remove($dep_target);
                            return 1;
                        }
                        return 0;
                    } ) == 1 && return undef;
                }
            }
        }

        return $self->recompute( $rule, $target, { map { $_ => $dep_values{$_}->[1]->value } keys %dep_values } )
          if $self->target_locked($rule);

        return CHI::Cascade::Value->new( state => $ret_state );
    };

    pop @{ $run_instance->{target_stack} };

    my $e = $@;

    if ( $self->target_locked($rule) ) {
        $self->target_unlock( $rule, $ret );
    }
    elsif ( $run_instance->{run_opts}{actual_term} && ! $only_from_cache && $run_instance->{orig_target} eq $target ) {
        $self->target_actual_stamp( $rule, $ret );
    }

    die $e if $e;

    return $ret || CHI::Cascade::Value->new;
}

lib/CHI/Cascade.pm  view on Meta::CPAN


=item chi

B<Required>. Instance of L<CHI> object. The L<CHI::Cascade> doesn't construct this
object for you. Please create instance of C<CHI> yourself.

=item busy_lock

B<Optional>. Default is I<never>. I<This is not C<busy_lock> option of CHI!>
This is amount of time (to see L<CHI/"DURATION EXPRESSIONS">) until all target
locks expire. When a target is to being computing it is locked. If process which
is to be computing target and it will die or OS will be hangs up we can dead
locks and locked target will never recomputed again. This option helps to avoid
it. You can set up a special busy_lock for rules too.

=item target_chi

B<Optional>. This is CHI cache for target markers. Default value is value of
L</chi> option. It can be useful if you use a L<CHI/l1_cache> option. So you can
separate data of targets from target markers - data will be kept in a file cache
and a marker in memory cache for example.

=back

lib/CHI/Cascade.pm  view on Meta::CPAN


B<Optional>. You can pass in your code any additional parameters by this option.
These parameters are accessed in your rule's code through
L<CHI::Cascade::Rule/params> method of L<CHI::Cascade::Rule> instance object.

=item busy_lock

B<Optional>. Default is L</busy_lock> of constructor or I<never> if first is not
defined. I<This is not C<busy_lock> option of CHI!> This is amount of time (to
see L<CHI/"DURATION EXPRESSIONS">) until target lock expires. When a target is
to being computed it is locked. If process which to be recomputing a target and
it will die or OS will be hangs up we can dead locks and locked target will
never recomputed again. This option helps to avoid it.

=item recomputed

B<Optional>. This is a computational callback (coderef). If target of this rule
was recomputed this callback will be executed right away after a recomputed
value has been saved in cache. The callback will be executed as $coderef->(
$rule, $target, $value ) where passed parameters are:

=over

lib/CHI/Cascade/Rule.pm  view on Meta::CPAN

    if (@_) {
        $self->{value_expires} = $_[0];
        return $self;
    }
    ( ref $self->{value_expires} eq 'CODE' ? $self->{value_expires}->( $self ) : $self->{value_expires} ) // 'never';
}

sub target_expires {
    my ( $self, $trg_obj ) = @_;

    $trg_obj->locked
        ?
        $self->{busy_lock} || $self->{cascade}{busy_lock} || 'never'
        :
        $trg_obj->expires // $trg_obj->expires( $self->value_expires );
}

sub ttl {
    my $self = shift;

    return undef

lib/CHI/Cascade/Target.pm  view on Meta::CPAN

use Time::HiRes;
use Time::Duration::Parse;

sub new {
    my ($class, %opts) = @_;

    bless { %opts }, ref($class) || $class;
}

sub lock {
    $_[0]->{locked} = $$;
}

sub locked {
    exists $_[0]->{locked}
      and $_[0]->{locked};
}

sub unlock {
    delete $_[0]->{locked};
}

sub time {
    $_[0]->{time} || 0;
}

sub touch {
    $_[0]->{time} = Time::HiRes::time;
    delete $_[0]->{finish_time};
    delete $_[0]->{expires_finish_time};



( run in 0.825 second using v1.01-cache-2.11-cpan-49f99fa48dc )