File Coverage

blib/lib/DynGig/Range/Cluster/Config.pm
Criterion Covered Total %
statement 33 115 28.7
branch 0 54 0.0
condition 0 21 0.0
subroutine 11 19 57.8
pod 3 6 50.0
total 47 215 21.8


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             DynGig::Range::Cluster::Config - Cluster configuration methods
4              
5             =cut
6             package DynGig::Range::Cluster::Config;
7              
8 1     1   8 use warnings;
  1         2  
  1         43  
9 1     1   5 use strict;
  1         2  
  1         32  
10 1     1   6 use Carp;
  1         2  
  1         68  
11              
12 1     1   1477 use YAML::XS;
  1         4007  
  1         61  
13 1     1   7 use File::Spec;
  1         2  
  1         19  
14 1     1   5 use Digest::MD5;
  1         1  
  1         9940  
15 1     1   16542 use Compress::Zlib;
  1         235106  
  1         1037  
16 1     1   11 use File::Spec;
  1         3  
  1         112  
17              
18 1     1   1129 use DynGig::Range::Cluster::EZDB;
  1         3  
  1         1359  
19              
20             my %_CONF;
21              
22             =head1 SYNOPSIS
23              
24             my $config = DynGig::Range::Cluster::Config->new( '/config/dir' );
25              
26             if ( my %update = $config->load() )
27             {
28             $config->update( %update );
29             }
30              
31             my $compressed = $config->zip();
32             my $md5 = $config->md5();
33              
34             =cut
35             sub new
36             {
37 0     0 0   my ( $class, $conf ) = @_;
38 0           my ( $file, $handle );
39              
40 0 0         croak 'conf directory not defined' unless defined $conf;
41 0 0         croak "$conf: $!" unless opendir $handle, $conf;
42              
43 0           while ( defined ( my $name = readdir $handle ) )
44             {
45 0 0 0       $_CONF{$name} = [ DynGig::Range::Cluster::EZDB->new( $file ) ]
46             if $name !~ /^\./o
47             && -f ( $file = File::Spec->join( $conf, $name ) );
48             }
49              
50 0           close $handle;
51 0   0       bless { cluster => {}, key => {}, value =>{} }, ref $class || $class;
52             }
53              
54             =head1 METHODS
55              
56             =head2 unzip()
57              
58             Returns decompressed config.
59              
60             =cut
61             sub unzip
62             {
63 0 0   0 1   return undef unless my $buffer = Compress::Zlib::uncompress( $_[0] );
64 0 0         return undef unless my $this = eval { YAML::XS::Load $buffer };
  0            
65 0 0         return ref $this eq __PACKAGE__ ? $this : undef;
66             }
67              
68             =head2 unzip()
69              
70             Returns compressed config.
71              
72             =cut
73             sub zip
74             {
75 0     0 0   my $serial = YAML::XS::Dump shift @_;
76              
77 0 0         return Compress::Zlib::compress( $serial ) unless @_;
78 0           return Compress::Zlib::compress( $serial, @_ );
79             }
80              
81             =head2 unzip()
82              
83             Returns MD5 digest of serialized config.
84              
85             =cut
86             sub md5
87             {
88 0     0 0   Digest::MD5->new()->add( YAML::XS::Dump $_[0] )->hexdigest();
89             }
90              
91             =head2 load()
92              
93             Delta loads ( no change == no-op ) configs into a HASH.
94             Returns HASH reference in scalar context.
95             Returns flattened HASH in list context.
96              
97             =cut
98             sub load
99             {
100 0     0 1   my $this = shift @_;
101 0           my %conf;
102              
103 0           for my $name ( keys %_CONF )
104             {
105 0           my $conf = $_CONF{$name};
106 0           my $mtime = ( $conf->[0]->stat() )[9];
107              
108 0 0 0       next if $conf->[1] && $mtime <= $conf->[1];
109              
110 0           $conf{$name} = $conf->[0]->reload()->get();
111 0           $conf->[1] = $mtime;
112             }
113              
114 0 0         return wantarray ? %conf : \%conf;
115             }
116              
117             =head2 update( cluster1 => config1, cluster2 => config2 .. )
118              
119             Updates object.
120              
121             =cut
122             sub update
123             {
124 0     0 1   my ( $this, %conf ) = @_;
125 0           my $K = $this->{key};
126 0           my $V = $this->{value};
127 0           my $C = $this->{cluster};
128              
129 0           for my $name ( keys %conf )
130             {
131 0           for my $table ( keys %$K )
132             {
133 0           for my $table ( $K->{$table}, $V->{$table} )
134             {
135 0           for my $key ( keys %$table )
136             {
137 0           delete $table->{$key}{$name};
138 0 0         delete $table->{$key} unless %{ $table->{$key} };
  0            
139             }
140             }
141             }
142              
143 0           while ( my ( $table, $conf ) = each %{ $C->{$name} = $conf{$name} } )
  0            
144             {
145 0           while ( my ( $key, $value ) = each %$conf )
146             {
147 0           $K->{$table}{$key}{$name} = $value;
148 0           push @{ $V->{$table}{$value}{$name} }, $key;
  0            
149             }
150             }
151             }
152             }
153              
154             sub AUTOLOAD
155             {
156 0     0     my $this = shift;
157 0           my $K = $this->{key};
158 0           my $V = $this->{value};
159              
160 0 0 0       if ( our $AUTOLOAD =~ /::DB_(\w+)$/ ) ## 'DB' methods
    0          
161             {
162 0           my $key = $1;
163              
164 0 0         if ( $key =~ /^(cluster|table)s$/ )
    0          
165             {
166 0 0         my @list = keys %{ $this->{$1} || $K };
  0            
167 0 0         return wantarray ? @list : \@list;
168             }
169             elsif ( $this->{$key} )
170             {
171 0           my $table = shift;
172 0 0         return defined $table ? $this->{$key}{$table} : $table;
173             }
174             }
175             elsif ( $AUTOLOAD =~ /::(\w+)$/ && $K->{$1} ) ## 'table' methods
176             {
177 0           my $table = $1;
178 0           my %param = @_;
179 0           my $key = $param{key};
180 0           my $value = $param{value};
181 0           my $cluster = $param{cluster};
182              
183 0 0 0       if ( defined $key && defined $value ) ## find clusters by key:value
    0          
184             {
185 0           my @list = grep { $K->{$table}{$key}{$_} eq $value }
  0            
186 0           keys %{ $K->{$table}{$key} };
187              
188 0 0         return wantarray ? @list : \@list;
189             }
190             elsif ( defined $cluster )
191             {
192 0 0         if ( defined $value ) ## find keys by cluster:value
    0          
193             {
194 0           my $list = $V->{$table}{$value}{$cluster};
195              
196 0 0 0       if ( $list && @$list == 1 && $list->[0] =~ /^##(.+)/ )
      0        
197             {
198 0           my $newlist = [];
199 0           my @param = split '_', $1;
200 0 0         if( @param >= 1 )
201             {
202 0           my $plugin = shift @param;
203 0           my $pfile = File::Spec->join(
204             "/devops/tools/var/range/plugin", $plugin );
205 0 0         if ( -f $pfile )
206             {
207             eval
208 0           {
209 1     1   9 no warnings;
  1         3  
  1         54  
210 1     1   7 no strict 'vars';
  1         18  
  1         221  
211 0           local $PARAM = \@param;
212 0           $newlist = do $pfile;
213             };
214             }
215             }
216 0           $list = $newlist;
217             }
218 0 0         return wantarray ? @$list : $list if $list;
    0          
219             }
220             elsif ( defined $key ) ## find value by cluster:key
221             {
222 0           return $K->{$table}{$key}{$cluster};
223             }
224             }
225             }
226              
227 0           return undef;
228             }
229              
230             sub DESTROY
231             {
232 0     0     my $this = shift @_;
233 0           map { delete $this->{$_} } keys %$this;
  0            
234             }
235              
236             ## a node may belong to more than one cluster.
237             ## hence it may have different status in different clusters
238              
239             =head1 NOTE
240              
241             See DynGig::Range::Cluster
242              
243             =cut
244              
245             1;
246              
247             __END__