Skip to content

Conversation

tomeon
Copy link

@tomeon tomeon commented Jul 10, 2016

CHI subclasses that define one or more subcaches using defaults, namespace, or storage are susceptible to infinite recursion upon get and set. Consider l1_loop.pl:

#!/usr/bin/env perl

use strict;
use warnings;

package My::CHI;                                   

use base 'CHI';                                    

__PACKAGE__->config({                              
    storage => {                                   
        local_file => {                                  
            driver      => 'File',                 
            root_dir    => '/tmp/mychi',           
        },
        raw_memory => {
               driver => 'RawMemory',
               global => 0,
        },                                       
    },                                             
    defaults => {                                  
        storage => 'local_file',                         
        l1_cache    => {                           
            storage => 'raw_memory',                     
        },                                         
    },                                             
});                                                

package main;                                      

my $cache = My::CHI->new;                          
$cache->set('it', 'off');
$ ./l1_loop.pl
Deep recursion on subroutine "Role::Tiny::_COMPOSABLE::CHI::Driver::Role::HasSubcaches::set" at /home/matt/git/perl-chi/lib/CHI/Driver/Role/HasSubcaches.pm line 88.
Deep recursion on anonymous subroutine at (eval 42) line 16.
^C

The reason is that the subcache is instantiated using the same defaults as the parent cache, so will have its own subcache, which has its own subcache, which has its own subcache, all the way down. This manifests as recursion on the anonymous subroutines defined with before and around in CHI::Driver::Role::HasSubcaches.

This pull requests addresses the infinite recursion issue by adding the constructor param no_defaults_for, which allows specifying a list of keys to delete from the defaults, namespace, and storage hashrefs prior to instantiating a CHI subclass instance. All subcaches get l1_cache and mirror_cache automatically appended to no_defaults_for -- only the parent cache can have subcaches defined from package defaults.

Thanks in advance for considering this pull request!


P.S.: I got the following error when running dzil build:

$ dzil build
Can't call method "content" on an undefined value at /home/matt/opt/perl5/perlbrew/perls/perl-5.20.0/lib/site_perl/5.20.0/Dist/Zilla/Plugin/MakeMaker.pm line 318.

I fixed this by editing dist.ini to remove filenames = Makefile.PL from [PruneFiles] and add exclude_filename = Makefile.PL to [GatherDir]. The real culprit might be some environment muck-up on my part -- please let me know :).

by adding the `no_defaults_for` constructor attribute, which (a) permits
specifying a list of keys to delete from the `defaults`, `namespace`,
and `storage` hashrefs prior to instantiating a CHI subclass instance,
and (b) mandatorily contains the keys `l1_cache` and `mirror_cache`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant