File Coverage

blib/lib/Collection/Utl/Mirror.pm
Criterion Covered Total %
statement 90 92 97.8
branch 16 22 72.7
condition n/a
subroutine 14 14 100.0
pod 1 2 50.0
total 121 130 93.0


line stmt bran cond sub pod time code
1             package Collection::Utl::Mirror;
2              
3             =head1 NAME
4              
5             Collection::Utl::Mirror - Mirror two collections.
6              
7             =head1 SYNOPSIS
8              
9             use Collection::Utl::Mirror;
10             my $coll1 = ( new Collection::Utl::Mem:: mem => \%h1 );# fast but nonstable source ( Memcached )
11             my $coll2 = ( new Collection::Utl::Mem:: mem => \%h2 );# slow but stable source ( database )
12              
13             my $mirror_coll1 = new Collection::Utl::Mirror:: $coll1, $coll2 ;
14              
15              
16             =head1 DESCRIPTION
17              
18             Mirror two collections.
19              
20            
21             =cut
22              
23 2     2   2205 use strict;
  2         4  
  2         108  
24 2     2   9 use warnings;
  2         6  
  2         51  
25 2     2   10 use strict;
  2         2  
  2         45  
26 2     2   10 use Carp;
  2         3  
  2         114  
27 2     2   9 use Data::Dumper;
  2         3  
  2         94  
28 2     2   10 use Test::More;
  2         2  
  2         14  
29             require Tie::Hash;
30 2     2   849 use Collection;
  2         4  
  2         1876  
31             @Collection::Utl::Mirror::ISA = qw(Collection);
32             $Collection::Utl::Mirror::VERSION = '0.02';
33              
34             __PACKAGE__->attributes (qw( _c1 _c2 _stack));
35              
36             sub Init {
37 1     1 0 2 my ( $self, $c1, $c2 ) = @_;
38 1         23 _c1 $self $c1;
39 1         21 _c2 $self $c2;
40 1         22 $self->_stack( [ $c1, $c2 ] );
41 1         8 return 1;
42             }
43              
44             sub _init {
45 1     1   3 my $self = shift;
46 1         8 $self->SUPER::_init(@_);
47 1         6 return $self->Init(@_);
48             }
49              
50             =head2 _fetch
51              
52             Fetch keys from collection1. And then from collection2
53              
54             =cut
55              
56             sub _fetch {
57 4     4   7 my $self = shift;
58              
59             #collect ids to fetch
60 4         9 my @ids = @_;
61 4 50       11 return {} unless @ids; #skip empty ids list
62 4         5 my ( $c1, $c2 ) = @{ $self->_stack };
  4         97  
63              
64             #read keys from first collection
65 4         17 my $res1 = $c1->fetch(@ids);
66 4         8 my @notfound = ();
67 4         5 foreach my $key (@ids) {
68 4 100       14 push @notfound, $key unless exists $res1->{$key};
69             }
70 4 100       12 if (@notfound) {
71              
72             #if we not found some keys, then fetch from coll2
73             #and store to coll1
74             # diag "Fetch non exists in col1".Dumper (\@notfound);
75 3         7 my $res2 = $c2->fetch(@notfound);
76 3         5 my %create_keys = ();
77 3         11 while ( my( $k1, $value ) = each %$res2 ) {
78              
79             #save results from $c2 storage in
80             #out put results
81 2         5 $res1->{$k1} = $value;
82             #save for create
83 2         7 $create_keys{$k1} = $value;
84             }
85 3 100       9 if ( keys %create_keys ) {
86              
87             # diag "create". Dumper (\%create_keys);
88             #store only simply results
89             #now store to coll1
90 2         11 my $created = $c1->create( %create_keys );
91             #if suss create use records from fast source
92 2         8 while ( my ( $key, $val) = each %create_keys ) {
93             #if fail create record in fast src
94             #use record from stable
95 2 50       5 next unless exists $created->{$key};
96 2         11 $res1->{$key} = $created->{$key};
97             }
98             }
99             }
100              
101             # diag "try " . Dumper( \@_ );
102             # diag "Diff two keys" . Dumper [ \@keys1, \@keys2 ];
103 4         19 return $res1;
104             }
105              
106             =head2 _create
107              
108             create items
109              
110             =cut
111              
112             sub _create {
113 1     1   2 my $self = shift;
114 1         2 my ( $c1, $c2 ) = @{ $self->_stack };
  1         21  
115 1         6 return $c2->create(@_);
116             }
117              
118             =head2 _store
119              
120             =cut
121              
122             sub _store {
123 2     2   3 my $self = shift;
124 2         4 my ( $c1, $c2 ) = @{ $self->_stack };
  2         46  
125 2         5 my $hash2store = shift;
126 2         6 my @ids2store = keys %$hash2store;
127 2         9 my $coll2res = $c2->fetch(@ids2store);
128             #and create new in col2
129             #create non exists keys on c2
130 2         5 my %tocreate = ();
131 2         7 while ( my ( $key, $val ) = each %$hash2store ) {
132 2 100       8 if ( exists $coll2res->{$key} ) {
133 1         2 my $value = $coll2res->{$key};
134              
135             #mirror only HASHes
136 1 50       5 if ( ref($val) eq 'HASH' ) {
    0          
137              
138             #use value as hash
139 1         4 %$value = %$val;
140             }
141             elsif ( UNIVERSAL::isa( $val, 'Collection::Utl::Item' ) ) {
142 0         0 %$value = %{$val->attr}
  0         0  
143              
144             }
145             }
146             else {
147              
148             #warn "resync source collections";
149             #syncing stable
150 1         5 $tocreate{$key} = $val;
151             }
152             }
153 2 100       8 if ( keys %tocreate ) {
154 1         5 $c2->create( \%tocreate );
155             }
156              
157             #now mirroring changed data
158             #mirror coll1 to coll2
159 2         7 while ( my ( $key, $val ) = each %$hash2store ) {
160 2 100       9 next unless exists $coll2res->{$key};
161            
162             }
163              
164             # changed items we also mirror to coll2
165 2         12 $c1->store(@ids2store);
166 2         7 $c2->store(@ids2store);
167 2         10 return;
168             }
169              
170             =head2 list_ids
171              
172             Return union of keys from collection1 and collection2
173              
174             =cut
175              
176             sub list_ids {
177 1     1 1 2 my $self = shift;
178 1         2 my ( $c1, $c2 ) = @{ $self->_stack };
  1         31  
179 1         2 my %uniq = ();
180 1         3 @uniq{ @{ $c1->list_ids }, @{ $c2->list_ids } } = ();
  1         5  
  1         4  
181 1         7 return [ keys %uniq ];
182             }
183              
184             sub _delete {
185 1     1   2 my $self = shift;
186 1         1 my ( $c1, $c2 ) = @{ $self->_stack };
  1         21  
187 1         2 my %res = ();
188 1         2 for ( $c1, $c2 ) {
189              
190             #save results
191 2 50       3 @res{ @{ $_->delete(@_) || [] } } = ();
  2         10  
192             }
193 1         5 [ keys %res ];
194             }
195             1;
196             __END__