perl-chi icon indicating copy to clipboard operation
perl-chi copied to clipboard

Add `no_defaults_for' attribute to fix subcache get/set infinite recursion

Open tomeon opened this issue 8 years ago • 0 comments

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 :).

tomeon avatar Jul 10 '16 20:07 tomeon