comparison lib/IMPL/Config/Bag.pm @ 415:3d24b10dd0d5 ref20150831

working on IMPL::Config::Container
author cin
date Tue, 20 Oct 2015 07:32:55 +0300
parents ec6f2d389d1e
children 3ed0c58e9da3
comparison
equal deleted inserted replaced
414:ec6f2d389d1e 415:3d24b10dd0d5
6 base => [ 6 base => [
7 'IMPL::Object' => undef 7 'IMPL::Object' => undef
8 ], 8 ],
9 props => [ 9 props => [
10 _parents => '*rw', # array of parent bags 10 _parents => '*rw', # array of parent bags
11 _state => '*rw', #array of previous timestamps 11 _parentRev => '*rw', # the timestamp of the parent
12 _sealed => '*rw', # the bag has descendants
12 _cache => '*rw', # own or cached entries 13 _cache => '*rw', # own or cached entries
13 _timestamp => '*rw', 14 _timestamp => '*rw',
14 _entries => '*rw', # each entry is represented by hash 15 _entries => '*rw', # each entry is represented by hash
15 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value } 16 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value }
16 ] 17 ]
18 19
19 sub CTOR { 20 sub CTOR {
20 my ( $this, $p ) = @_; 21 my ( $this, $p ) = @_;
21 22
22 if ($p) { 23 if ($p) {
24 $p->_Seal();
23 my @parents; 25 my @parents;
24 push @parents, @{ $p->{$_parents} } if $p->{$_parents}; 26 push @parents, @{ $p->{$_parents} } if $p->{$_parents};
25 push @parents, $p; 27 push @parents, $p;
26 $this->{$_parents} = \@parents; 28 $this->{$_parents} = \@parents;
27 $this->{$_state} = [ map $_->{$_timestamp}, @parents ]; 29 $this->{$_parentRev} = $p->{$_timestamp};
28 } 30 }
29 31
30 $this->{$_timestamp} = 0; 32 $this->{$_timestamp} = 0;
31 $this->{$_cache} = {}; 33 $this->{$_cache} = {};
32 $this->{$_entries} = []; 34 $this->{$_entries} = [];
33 } 35 }
34 36
35 sub GetParent { 37 sub GetParent {
36 $_[0]->{$_parents} && $_[0]->{$_parents}[0]; 38 my ($this) = @_;
39
40 $this->{$_parents} && $this->{$_parents}[ @{ $this->{$_parents} } - 1 ];
41 }
42
43 sub _Seal {
44 unless ($_[0]->{$_sealed}) {
45 $_[0]->{$_sealed} = 1;
46 $_[0]->{$_timestamp} = 0; # from now the timestamp is important
47 }
37 } 48 }
38 49
39 sub _Validate { 50 sub _Validate {
40 my ($this) = @_; 51 my ($this) = @_;
41 52
42 my $parents = $this->{$_parents} 53 my $chain = $this->{$_parents}
43 or return; 54 or return 1;
44 my $state = $this->{$_state}; 55
45 my $len = @$parents; 56 my $rev = 0; # rev 0 means that parent was never modified
57 # this allows to made more efficient checks
46 my $flush; 58 my $flush;
47 59
48 for ( my $i = 0 ; $i < $len ; $i++ ) { 60 foreach my $bag (@$chain, $this) {
49 if ($flush) { 61 # we need to updated all bags after the first change was detected;
50 $parents->[$i]{$_cache} = {}; 62 if ($flush ||= $rev and $bag->{$_parentRev} != $rev) {
51 $state->[$i] = $parents->[$i]{$_timestamp}; 63 $bag->{$_cache} = {};
52 } 64 $bag->{$_parentRev} = $rev;
53 else { 65 }
54 $flush = ( $parents->[$i]{$_timestamp} != $state->[$i] ); 66 $rev = $bag->{$_timestamp};
55 }
56 } 67 }
57 68
58 if ($flush) { 69 return $flush ? 0 : 1;
59 $this->{$_cache} = {};
60 return 0;
61 }
62
63 return 1;
64 } 70 }
65 71
66 sub Resolve { 72 sub Resolve {
67 my ( $this, $role ) = @_; 73 my ( $this, $role ) = @_;
68 74
69 if ( my $d = $this->GetDescriptor() ) { 75 die IMPL::InvalidArgumentException->new('role')
76 unless defined $role;
77
78 if ( my $d = $this->_GetDescriptor($role) ) {
70 return $d->{value}; 79 return $d->{value};
71 } 80 }
72 else { 81 else {
73 return; 82 return;
74 } 83 }
75 } 84 }
76 85
77 sub GetDescriptor { 86 sub _GetDescriptor {
78 my ( $this, $role ) = @_; 87 my ( $this, $role ) = @_;
79 88
80 my $d = $this->{$_cache}{$role}; 89 my $d = $this->{$_cache}{$role};
81 90
82 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache) 91 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache)
83 # otherwise the cache must be validated 92 # otherwise the cache must be validated
84 return $d 93 return $d
85 if $d 94 if $d
86 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 ) 95 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 )
87 or $this->_Validate() ); 96 or $this->_Validate() );
97
98 # if there were no descriptor in cache we need to ensure that the cache
99 # chain is valid before reolving starts
100 $this->_Validate() unless $d;
88 101
89 # the cache chain is valid 102 # the cache chain is valid
90 # $d is not a valid descriptor 103 # $d is not a valid descriptor
91 104
92 $d = undef; 105 $d = undef;
125 my ( $this, $role ) = @_; 138 my ( $this, $role ) = @_;
126 139
127 return [ 140 return [
128 map $_->{value}, 141 map $_->{value},
129 grep $_->{isa}{$role}, 142 grep $_->{isa}{$role},
130 map $_->{$_entries}, 143 map @{$_->{$_entries}},
131 @{ $this->{$_parents} || [] }, 144 @{ $this->{$_parents} || [] },
132 $this 145 $this
133 ]; 146 ];
134 147
135 } 148 }
136 149
137 sub Register { 150 sub Register {
138 my ( $this, $isa, $value ) = @_; 151 my ( $this, $isa, $value ) = @_;
139 152
140 $isa = { $isa, 1 } unless isHash($isa); 153 $isa = { $isa, 1 } unless ishash($isa);
141 154
142 push @{ $this->{$_entries} }, 155 push @{ $this->{$_entries} },
143 { owner => $this, isa => $isa, value => $value }; 156 { owner => $this, isa => $isa, value => $value };
144 $this->{$_timestamp}++; 157 $this->{$_timestamp}++;
145 158