File Coverage

blib/lib/Apache/Hadoop/Config.pm
Criterion Covered Total %
statement 8 164 4.8
branch 0 62 0.0
condition 0 39 0.0
subroutine 3 25 12.0
pod 0 9 0.0
total 11 299 3.6


line stmt bran cond sub pod time code
1             package Apache::Hadoop::Config;
2              
3 1     1   19761 use 5.010001;
  1         3  
4 1     1   5 use strict;
  1         2  
  1         20  
5 1     1   4 use warnings;
  1         10  
  1         2471  
6              
7             our @ISA = qw();
8             our $VERSION = '0.01';
9              
10              
11             # class definition begins
12              
13             sub new {
14 0     0 0   my $class = shift;
15 0           my %args = @_;
16             my $self = {
17             namenode => $args{'namenode'} || 'localhost',
18             secondary => $args{'secondary'} || '0.0.0.0',
19             proxynode => $args{'proxynode'} || 'localhost',
20             proxyport => $args{'proxyport'} || 8888,
21             hadoop_install => $args{'hadoop_install'} || '/usr/local/hadoop',
22             hadoop_confdir => $args{'hadoop_confdir'} || '/usr/local/hadoop/etc/hadoop',
23             hdfs_tmp => $args{'hdfs_tmp'} || '/hdfs/tmp',
24             hdfs_name_disks=> $args{'hdfs_name_disks'} ||
25             [ '/hdfs/name1',
26             '/hdfs/name2',
27             ],
28             hdfs_data_disks=> $args{'hdfs_data_disks'} ||
29             [ '/hdfs/data1',
30             '/hdfs/data2',
31             '/hdfs/data3',
32             '/hdfs/data4',
33             ],
34             hadoop_logs => [ '/logs', '/logs/userlog' ],
35             debug => $args{'debug'} || undef,
36              
37             config => $args{'config'} || undef,
38              
39             sysinfo=> {
40             cpu => $args{'cpuinfo'} || undef,
41             mem => $args{'meminfo'} || undef,
42 0   0       disk => $args{'diskinfo'} || undef,
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
43             },
44             };
45 0           bless $self, $class;
46 0           return $self;
47             }
48              
49             # internal utils
50             sub _minimum {
51 0     0     my ($self, @arr) = (@_);
52 0           my $min;
53 0 0 0       for (@arr) { $min = $_ if !$min || $_ < $min; }
  0            
54 0           return $min;
55             }
56              
57             sub _maximum {
58 0     0     my ($self, @arr) = (@_);
59 0           my $max;
60 0 0 0       for (@arr) { $max = $_ if !$max || $_ > $max; }
  0            
61 0           return $max;
62             }
63              
64             sub _copyconf {
65 0     0     my ($self, $config) = (@_);
66 0 0         unless ( defined $self->{'config'} ) {
67 0           $self->{'config'} = $config;
68 0           return;
69             }
70              
71 0           foreach my $file ( keys %{$config} ) {
  0            
72 0           foreach my $param ( keys %{$config->{$file}} ) {
  0            
73             $self->{'config'}->{$file}->{$param} = $config->{$file}->{$param}
74 0 0         unless defined $self->{'config'}->{$file}->{$param};
75             }
76             }
77             }
78              
79             # get config template
80             sub basic_config {
81 0     0 0   my ($self) = (@_);
82             my $config = {
83             'core-site.xml' => {
84             'fs.defaultFS' => 'http://'.$self->{namenode}.':9000',
85             'hadoop.tmp.dir' => $self->{'hdfs_tmp'},
86             },
87             'hdfs-site.xml' => {
88             'dfs.replication' => 1,
89 0           'dfs.namenode.name.dir' => join ( ',', map { 'file://'.$_ } @{$self->{'hdfs_name_disks'}} ),
  0            
90 0           'dfs.datanode.data.dir' => join ( ',', map { 'file://'.$_ } @{$self->{'hdfs_data_disks'}} ),
  0            
91              
92             # secondary namenode
93             'dfs.namenode.secondary.http-address' => $self->{'secondary'}.':50090',
94             'dfs.namenode.secondary.https-address'=> $self->{'secondary'}.':50091',
95             },
96             'yarn-site.xml' => {
97             'yarn.nodemanager.aux-services' => 'mapreduce_shuffle',
98             'yarn.nodemanager.aux-services.mapreduce.shuffle.class' => 'org.apache.hadoop.mapred.ShuffleHandler',
99 0           'yarn.web-proxy.address' => $self->{'proxynode'}.':'.$self->{'proxyport'},
100             },
101             'mapred-site.xml' => {
102             'mapreduce.framework.name' => 'yarn',
103             }
104             };
105            
106 0           $self->_copyconf ( $config );
107             }
108              
109             #
110             # directory management
111             #
112             sub _mkdir {
113 0     0     my ($self, %opts) = (@_);
114 0   0       my $mode = $opts{'mode'} || 0750;
115 0           my $u = umask (0);
116 0           map { mkdir $_, $mode; chdir $_; } split (/\//, $opts{'directory'});
  0            
  0            
117             }
118              
119             sub create_hdfs_name_disks {
120 0     0 0   my ($self) = (@_);
121 0           foreach my $dir ( @{$self->{'hdfs_name_disks'}} ) {
  0            
122 0 0         print "creating ".$dir, "\n" if defined $self->{'debug'};
123 0           $self->_mkdir( directory => $dir );
124             }
125             }
126              
127             sub create_hdfs_data_disks {
128 0     0 0   my ($self) = (@_);
129 0           foreach my $dir ( @{$self->{'hdfs_data_disks'}} ) {
  0            
130 0 0         print "creating ".$dir, "\n" if defined $self->{'debug'};
131 0           $self->_mkdir( directory => $dir );
132             }
133             }
134              
135             sub create_hdfs_tmpdir {
136 0     0 0   my ($self) = (@_);
137 0 0         print "creating ".$self->{'hdfs_tmp'}, "\n" if defined $self->{'debug'};
138 0           $self->_mkdir( directory => $self->{'hdfs_tmp'}, mode => 01775 );
139             }
140              
141             sub create_hadoop_logdir {
142             # $hadoop_install/tmp 1775
143 0     0 0   my ($self) = (@_);
144 0           foreach my $dir ( @{$self->{'hadoop_logs'}} ) {
  0            
145 0 0         print "creating ".$self->{'hadoop_install'}.$dir, "\n" if defined $self->{'debug'};
146 0           $self->_mkdir( directory => $self->{'hadoop_install'}.$dir, mode => 01775 );
147             }
148             }
149             # ends
150              
151             #
152             # begin recommended settings
153             #
154              
155             # get cpu core count
156             sub _get_cpu_cores {
157 0     0     my ($self) = (@_);
158 0           my $cpuinfo = '/proc/cpuinfo';
159 0 0         open CPU, $cpuinfo or die "Cannot open $cpuinfo, $!\n";
160 0           $self->{'sysinfo'}->{'cpu'} = scalar (map /^processor/, );
161 0           close CPU;
162             }
163              
164             # get memory size
165             sub _get_memory_system {
166 0     0     my ($self) = (@_);
167 0           my $meminfo = '/proc/meminfo';
168 0 0         open MEM, $meminfo or die "Cannot open $meminfo, $!\n";
169 0           $self->{'sysinfo'}->{'mem'} = (split (/\s+/, (grep /^MemTotal/, )[0]))[1];
170 0           $self->{'sysinfo'}->{'mem'} = $self->{'sysinfo'}->{'mem'} / (1024.0 * 1024.0);
171 0           close MEM;
172             }
173              
174             # get disk info: not implemented
175             sub _get_disk_count {
176 0     0     my ($self) = (@_);
177 0           $self->{'sysinfo'}->{'disk'} = scalar @{$self->{'hdfs_data_disks'}}
  0            
178             }
179              
180             # calculate reserved memory
181             sub _get_memory_reserved {
182 0     0     my ($self) = (@_);
183 0           my ($m, $m1, $m2, $m3);
184              
185 0 0         $self->_get_memory_system unless defined $self->{'sysinfo'}->{'mem'};
186 0           $m = $self->{'sysinfo'}->{'mem'};
187 0           $m1 = int (0.124102 * $m + 1.236659); # approximated by a linear eq through least square
188 0 0         $m2 = $m >= 16 ? $m1 - ($m1%2) : $m1;
189 0 0         $m3 = $m >= 64 ? $m2 - ($m2%2) : $m2;
190 0 0         print "reserved_mem (gb): ",$m3,"\n" if $self->{'debug'};
191 0           return $m3;
192             }
193              
194             # calculate available memory (total - reserved)
195             sub _calc_memory_available {
196 0     0     my ($self) = (@_);
197 0 0         $self->_get_memory_system unless defined $self->{'sysinfo'}->{'mem'};
198 0           my $mem = $self->{'sysinfo'}->{'mem'} - $self->_get_memory_reserved;
199 0           $mem *= 1024; # mb
200 0 0         print "available mem (mb): $mem\n" if $self->{'debug'};
201 0           return $mem;
202             }
203              
204             # calculate min container size
205             sub _calc_min_container_size {
206 0     0     my ($self) = (@_);
207 0 0         $self->_get_memory_system unless defined $self->{'sysinfo'}->{'mem'};
208 0           my $m = $self->{'sysinfo'}->{'mem'};
209 0 0         my $m1 = $m < 4 ? 0 : ($m < 8 ? 1 : ($m<24 ? 2 : 3));
    0          
    0          
210 0           my $m2 = 2 ** $m1;
211 0           my $m3 = 0.25 * $m2 * 1024; # mb
212 0 0         print "min_container_size (mb): $m3\n" if $self->{'debug'};
213 0           return $m3;
214             }
215              
216             sub _calc_container_count {
217 0     0     my ($self) = (@_);
218 0           my ($cores, $disks);
219 0           my $ratio = $self->_calc_memory_available / $self->_calc_min_container_size;
220              
221 0 0         $self->_get_cpu_cores unless defined $self->{'sysinfo'}->{'cpu'};
222 0           $cores = 2 * $self->{'sysinfo'}->{'cpu'};
223              
224 0 0         unless (defined $self->{'sysinfo'}->{'disk'}) { $self->_get_disk_count; }
  0            
225 0           $disks = 1.8 * $self->{'sysinfo'}->{'disk'};
226              
227 0 0         print "cores=$cores disks=$disks ratio=$ratio\n" if $self->{'debug'};
228 0           return int ($self->_minimum($cores, $disks, $ratio));
229             }
230              
231             sub _calc_container_memory {
232 0     0     my ($self) = (@_);
233 0           my $ratio = $self->_calc_memory_available / $self->_calc_container_count;
234 0           my $size = $self->_calc_min_container_size;
235 0           return int($self->_maximum($size, $ratio));
236             }
237              
238             sub memory_config {
239 0     0 0   my ($self) = (@_);
240              
241 0           my $con = $self->_calc_container_count;
242 0           my $mpc = $self->_calc_container_memory;
243              
244 0           my $config = {
245             'yarn-site.xml' => {
246             'yarn.nodemanager.resource.memory-mb' => $con * $mpc,
247             'yarn.scheduler.minimum-allocation-mb' => $mpc,
248             'yarn.scheduler.maximum-allocation-mb' => $con * $mpc,
249             },
250             'mapred-site.xml' => {
251             'mapreduce.map.memory.mb' => $mpc,
252             'mapreduce.reduce.memory.mb' => 2 * $mpc,
253             'mapreduce.map.java.opts' => "-Xmx".int(0.8 * $mpc)."m",
254             'mapreduce.reduce.java.opts' => "-Xmx".int(0.8 * 2 * $mpc)."m",
255             },
256             };
257 0           $self->_copyconf ( $config );
258             }
259              
260             sub print_config {
261 0     0 0   my ($self) = (@_);
262              
263 0           print "min cont size (mb) : ",$self->_calc_min_container_size,"\n";
264 0           print "num of containers : ",$self->_calc_container_count,"\n";
265 0           print "mem per container (mb): ",$self->_calc_container_memory,"\n";
266 0           foreach my $k ( keys %{$self->{'sysinfo'}} ) {
  0            
267             print sprintf "%5s : %s\n", $k, $self->{'sysinfo'}->{$k}
268 0 0         if defined $self->{'sysinfo'}->{$k};
269             }
270              
271 0           print "---------------\n";
272 0           foreach my $file ( keys %{$self->{'config'}} ) {
  0            
273 0           print $file, "\n";
274 0           my $val = $self->{'config'}->{$file};
275 0           foreach my $key ( keys %$val ) {
276 0           print " ",$key,": ", $val->{$key},"\n";
277             }
278             }
279 0           print "---------------\n";
280             }
281              
282             sub _tag {
283 0     0     my ($self, %args) = (@_);
284              
285 0           my $header = qq{
286            
287            
300              
301            
302             };
303              
304 0           my $property = qq{
305             NAME
306             VALUE
307            
308             };
309             # type = header, config, property
310             # (type=config) begin=>1, end=>1
311             # (type==property) name=>s value=>s
312             #
313 0           for ($args{'type'}) {
314 0 0         /header/ && do {
315 0           return $header;
316             };
317 0 0         /config/ && do {
318 0           my $str;
319 0 0         $str .= "\n" if defined $args{'begin'};
320 0 0         $str .= "\n" if defined $args{'end'};
321 0           return $str;
322             };
323 0 0         /property/ && do {
324 0           my $str = $property;
325 0           $str =~ s/NAME/$args{'name'}/;
326 0           $str =~ s/VALUE/$args{'value'}/;
327 0           return $str;
328             };
329             }
330             }
331            
332             sub write_config {
333 0     0 0   my ($self, %args) = (@_);
334 0   0       my $cdir = $args{'confdir'} || $self->{'confdir'};
335            
336 0           foreach my $file ( keys %{$self->{'config'}} ) {
  0            
337 0           print "-> writing to $cdir/$file ...\n";
338              
339             # open conf file
340 0 0         open CONF, ">".$cdir.'/'.$file or die $!;
341              
342             # xml header
343 0           print CONF $self->_tag (type=>'header');
344 0           print CONF $self->_tag (type=>'config', begin=>1);
345              
346             # properties
347 0           my $prop = $self->{'config'}->{$file};
348 0           foreach my $key ( keys %{$prop} ) {
  0            
349 0           print CONF $self->_tag( type=>'property', name=>$key, value=>$prop->{$key} );
350             }
351              
352             # close config
353 0           print CONF $self->_tag (type=>'config', end=>1);
354 0           close CONF;
355             }
356             }
357             #
358             # ends recommended settings
359              
360             1;
361             __END__