File Coverage

blib/lib/MCE/Core/Validation.pm
Criterion Covered Total %
statement 134 167 80.2
branch 85 150 56.6
condition 45 103 43.6
subroutine 9 9 100.0
pod n/a
total 273 429 63.6


line stmt bran cond sub pod time code
1             ###############################################################################
2             ## ----------------------------------------------------------------------------
3             ## Core validation methods for Many-Core Engine.
4             ##
5             ## This package provides validation methods used internally by the manager
6             ## process.
7             ##
8             ## There is no public API.
9             ##
10             ###############################################################################
11              
12             package MCE::Core::Validation;
13              
14 94     94   657 use strict;
  94         177  
  94         3620  
15 94     94   710 use warnings;
  94         319  
  94         9885  
16              
17             our $VERSION = '1.902';
18              
19             ## Items below are folded into MCE.
20              
21             package # hide from rpm
22             MCE;
23              
24 94     94   627 no warnings qw( threads recursion uninitialized );
  94         157  
  94         332599  
25              
26             ###############################################################################
27             ## ----------------------------------------------------------------------------
28             ## Validation method (attributes allowed for top-level).
29             ##
30             ###############################################################################
31              
32             sub _validate_args {
33              
34 440     440   1170 my $_s = $_[0];
35              
36 440         889 @_ = ();
37              
38 440         1011 my $_tag = 'MCE::_validate_args';
39              
40 440 100 100     2742 if (defined $_s->{input_data} && ref $_s->{input_data} eq '') {
41             _croak("$_tag: ($_s->{input_data}) does not exist")
42 18 50       416 unless (-e $_s->{input_data});
43             }
44              
45 440         1224 for my $_k (qw(job_delay spawn_delay submit_delay loop_timeout)) {
46             _croak("$_tag: ($_k) is not valid")
47 1760 0 0     4140 if ($_s->{$_k} && (!looks_like_number($_s->{$_k}) || $_s->{$_k} < 0));
      33        
48             }
49 440         1066 for my $_k (qw(freeze thaw on_post_exit on_post_run user_error user_output)) {
50             _croak("$_tag: ($_k) is not a CODE reference")
51 2640 50 66     8456 if ($_s->{$_k} && ref $_s->{$_k} ne 'CODE');
52             }
53              
54 440         1868 _validate_args_s($_s);
55              
56 440 100       4168 if (defined $_s->{user_tasks}) {
57 267         672 for my $_t (@{ $_s->{user_tasks} }) {
  267         842  
58 416         1122 _validate_args_s($_s, $_t);
59             }
60             }
61              
62 440         1321 return;
63             }
64              
65             ###############################################################################
66             ## ----------------------------------------------------------------------------
67             ## Validation method (top-level and sub-tasks).
68             ##
69             ###############################################################################
70              
71             sub _validate_args_s {
72              
73 856   66 856   1369 my $self = $_[0]; my $_s = $_[1] || $self;
  856         2609  
74              
75 856         1420 @_ = ();
76              
77 856         1651 my $_tag = 'MCE::_validate_args_s';
78              
79 856 50       2269 if (defined $_s->{max_workers}) {
80 856         2136 $_s->{max_workers} = _parse_max_workers($_s->{max_workers});
81              
82             _croak("$_tag: (max_workers) is not valid")
83 856 50       4892 if ($_s->{max_workers} !~ /\A\d+\z/);
84             }
85              
86 856 100       2041 if (defined $_s->{chunk_size}) {
87 440 50       2466 if ($_s->{chunk_size} =~ /([0-9\.]+)K\z/i) {
    50          
88 0         0 $_s->{chunk_size} = int($1 * 1024 + 0.5);
89             }
90             elsif ($_s->{chunk_size} =~ /([0-9\.]+)M\z/i) {
91 0         0 $_s->{chunk_size} = int($1 * 1024 * 1024 + 0.5);
92             }
93              
94             _croak("$_tag: (chunk_size) is not valid")
95 440 50 33     3687 if ($_s->{chunk_size} !~ /\A[0-9e\+]+\z/ or $_s->{chunk_size} == 0);
96              
97 440         1040 $_s->{chunk_size} = int($_s->{chunk_size});
98             }
99              
100             _croak("$_tag: (RS) is not valid")
101 856 50 33     2278 if ($_s->{RS} && ref $_s->{RS} ne '');
102             _croak("$_tag: (max_retries) is not valid")
103 856 50 33     2161 if ($_s->{max_retries} && $_s->{max_retries} !~ /\A\d+\z/);
104              
105 856         1953 for my $_k (qw(progress user_begin user_end user_func task_end)) {
106             _croak("$_tag: ($_k) is not a CODE reference")
107 4280 50 66     10611 if ($_s->{$_k} && ref $_s->{$_k} ne 'CODE');
108             }
109              
110 856 100       2276 if (defined $_s->{gather}) {
111 287         908 my $_ref = ref $_s->{gather};
112              
113 287 50 66     2911 _croak("$_tag: (gather) is not a valid reference")
      100        
      66        
      66        
114             if ( $_ref ne 'MCE::Queue' && $_ref ne 'Thread::Queue' &&
115             $_ref ne 'ARRAY' && $_ref ne 'HASH' && $_ref ne 'CODE' );
116             }
117              
118 856 100       2016 if (defined $_s->{sequence}) {
119 18         100 my $_seq = $_s->{sequence};
120              
121 18 50       71 if (ref $_seq eq 'ARRAY') {
122 18         33 my ($_begin, $_end, $_step, $_fmt) = @{ $_seq };
  18         52  
123 18         365 $_seq = {
124             begin => $_begin, end => $_end, step => $_step, format => $_fmt
125             };
126             }
127             else {
128 0 0       0 _croak("$_tag: (sequence) is not a HASH or ARRAY reference")
129             if (ref $_seq ne 'HASH');
130             }
131              
132 18         356 for my $_k (qw(begin end)) {
133             _croak("$_tag: ($_k) is not defined for sequence")
134 36 50       99 unless (defined $_seq->{$_k});
135             }
136              
137 18         87 for my $_p (qw(begin end step)) {
138             _croak("$_tag: ($_p) is not valid for sequence")
139 54 50 66     357 if (defined $_seq->{$_p} && !looks_like_number($_seq->{$_p}));
140             }
141              
142 18 50       51 unless (defined $_seq->{step}) {
143 18 50       52 $_seq->{step} = ($_seq->{begin} <= $_seq->{end}) ? 1 : -1;
144 18 50       68 if (ref $_s->{sequence} eq 'ARRAY') {
145 18         42 $_s->{sequence}->[2] = $_seq->{step};
146             }
147             }
148              
149 18 50       60 if (ref $_s->{sequence} eq 'HASH') {
150 0         0 for my $_k ('begin', 'end', 'step') {
151             $_s->{sequence}{$_k} = int($_s->{sequence}{$_k})
152 0 0       0 unless ($_s->{sequence}{$_k} =~ /\./);
153             }
154             }
155             else {
156 18         64 for my $_i (0, 1, 2) {
157             $_s->{sequence}[$_i] = int($_s->{sequence}[$_i])
158 54 50       240 unless ($_s->{sequence}[$_i] =~ /\./);
159             }
160             }
161              
162 18 50 33     410 if ( ($_seq->{step} < 0 && $_seq->{begin} < $_seq->{end}) ||
      33        
      33        
      33        
163             ($_seq->{step} > 0 && $_seq->{begin} > $_seq->{end}) ||
164             ($_seq->{step} == 0)
165             ) {
166 0         0 _croak("$_tag: impossible (step size) for sequence");
167             }
168             }
169              
170 856 50       2163 if (defined $_s->{interval}) {
171 0 0       0 if (ref $_s->{interval} eq '') {
172 0         0 $_s->{interval} = { delay => $_s->{interval} };
173             }
174              
175 0         0 my $_i = $_s->{interval};
176              
177 0 0       0 _croak("$_tag: (interval) is not a HASH reference")
178             if (ref $_i ne 'HASH');
179             _croak("$_tag: (delay) is not defined for interval")
180 0 0       0 unless (defined $_i->{delay});
181             _croak("$_tag: (delay) is not valid for interval")
182 0 0 0     0 if (!looks_like_number($_i->{delay}) || $_i->{delay} < 0);
183              
184 0         0 for my $_p (qw(max_nodes node_id)) {
185             _croak("$_tag: ($_p) is not valid for interval")
186             if (defined $_i->{$_p} && (
187             !looks_like_number($_i->{$_p}) ||
188             int($_i->{$_p}) != $_i->{$_p} ||
189 0 0 0     0 $_i->{$_p} < 1
      0        
190             ));
191             }
192              
193 0 0       0 $_i->{max_nodes} = 1 unless (exists $_i->{max_nodes});
194 0 0       0 $_i->{node_id} = 1 unless (exists $_i->{node_id});
195 0         0 $_i->{_time} = MCE::Util::_time();
196             }
197              
198 856         1889 return;
199             }
200              
201             ###############################################################################
202             ## ----------------------------------------------------------------------------
203             ## Validation method (run state).
204             ##
205             ###############################################################################
206              
207             sub _validate_runstate {
208              
209 173     173   569 my $self = $_[0]; my $_tag = $_[1];
  173         514  
210              
211 173         353 @_ = ();
212              
213             _croak("$_tag: method is not allowed by the worker process")
214 173 50       698 if ($self->{_wid});
215             _croak("$_tag: method is not allowed while processing")
216 173 50       604 if ($self->{_send_cnt});
217             _croak("$_tag: method is not allowed while running")
218 173 50       625 if ($self->{_total_running});
219              
220 173         443 return;
221             }
222              
223             ###############################################################################
224             ## ----------------------------------------------------------------------------
225             ## Private functions for MCE Models { Flow, Grep, Loop, Map, Step, Stream }.
226             ##
227             ###############################################################################
228              
229             sub _parse_chunk_size {
230              
231 187     187   1411 my ($_chunk_size, $_max_workers, $_params, $_input_data, $_array_size) = @_;
232              
233 187         444 @_ = ();
234              
235 187 50 33     1727 return $_chunk_size if (!defined $_chunk_size || !defined $_max_workers);
236              
237 187 50 33     1225 if (defined $_params && exists $_params->{chunk_size}) {
238 0         0 $_chunk_size = $_params->{chunk_size};
239             }
240              
241 187 50       1465 if ($_chunk_size =~ /([0-9\.]+)K\z/i) {
    50          
242 0         0 $_chunk_size = int($1 * 1024 + 0.5);
243             }
244             elsif ($_chunk_size =~ /([0-9\.]+)M\z/i) {
245 0         0 $_chunk_size = int($1 * 1024 * 1024 + 0.5);
246             }
247              
248 187 50       728 if ($_chunk_size eq 'auto') {
249              
250 187 50 33     2205 if ( (defined $_params &&
      66        
      33        
251             ref $_params->{input_data} =~ /^(?:CODE|Iterator::)/) ||
252             (defined $_input_data &&
253             ref $_input_data =~ /^(?:CODE|Iterator::)/)
254             ) {
255             # Iterators may optionally use chunk_size to determine how much
256             # to return per iteration. The default is 1 for MCE Models, same
257             # as for the Core API. The user_func receives an array_ref
258             # regardless if 1 or greater.
259             #
260             # sub make_iter {
261             # ...
262             # return sub {
263             # my ($chunk_size) = @_;
264             # ...
265             # };
266             # }
267 0         0 return 1;
268             }
269              
270 187         426 my $_is_file;
271 187         414 my $_size = $_array_size;
272              
273 187 100       786 if (defined $_input_data) {
274 24 100       132 if (ref $_input_data eq 'ARRAY') {
    50          
275 18         37 $_size = scalar @{ $_input_data };
  18         58  
276             } elsif (ref $_input_data eq 'HASH') {
277 6         12 $_size = scalar keys %{ $_input_data };
  6         22  
278             }
279             }
280              
281 187 100 66     2708 if (defined $_params && exists $_params->{sequence}) {
    100 33        
    100          
282 18         39 my ($_begin, $_end, $_step);
283              
284 18 50       71 if (ref $_params->{sequence} eq 'HASH') {
285 0         0 $_begin = $_params->{sequence}->{begin};
286 0         0 $_end = $_params->{sequence}->{end};
287 0   0     0 $_step = $_params->{sequence}->{step} || 1;
288             }
289             else {
290 18         37 $_begin = $_params->{sequence}[0];
291 18         32 $_end = $_params->{sequence}[1];
292 18   50     90 $_step = $_params->{sequence}[2] || 1;
293             }
294              
295 18 50 33     181 if (!defined $_input_data && !$_array_size) {
296 18         67 $_size = abs($_end - $_begin) / $_step + 1;
297             }
298             }
299             elsif (defined $_params && exists $_params->{_file}) {
300 36         141 my $_ref = ref $_params->{_file};
301              
302 36 50       172 if ($_ref eq 'SCALAR') {
    100          
303 0         0 $_size = length ${ $_params->{_file} };
  0         0  
304             } elsif ($_ref eq '') {
305 18         439 $_size = -s $_params->{_file};
306             } else {
307 18         53 $_size = 0; $_chunk_size = 393_216; # 384K
  18         41  
308             }
309              
310 36         82 $_is_file = 1;
311             }
312             elsif (defined $_input_data) {
313 24 50       334 if (ref($_input_data) =~ /^(?:GLOB|FileHandle|IO::)/) {
    50          
314 0         0 $_is_file = 1; $_size = 0; $_chunk_size = 393_216; # 384K
  0         0  
  0         0  
315             }
316             elsif (ref $_input_data eq 'SCALAR') {
317 0         0 $_is_file = 1; $_size = length ${ $_input_data };
  0         0  
  0         0  
318             }
319             }
320              
321 187 100       613 if (defined $_is_file) {
322 36 100       123 if ($_size) {
323 18         73 $_chunk_size = int($_size / $_max_workers / 24 + 0.5);
324 18 50       72 $_chunk_size = 5_242_880 if $_chunk_size > 5_242_880; # 5M
325 18 50       63 if ($_chunk_size <= 8192) {
326 18 100       185 $_chunk_size = (caller() =~ /^MCE::(?:Grep|Map|Stream)/) ? 1 : 2;
327             }
328             }
329             }
330             else {
331 151         693 $_chunk_size = int($_size / $_max_workers / 24 + 0.5);
332 151 50       710 $_chunk_size = 8000 if $_chunk_size > 8000;
333 151 50       789 if ($_chunk_size < 2) {
334 151 100       1562 $_chunk_size = (caller() =~ /^MCE::(?:Grep|Map|Stream)/) ? 1 : 2;
335             }
336             }
337             }
338              
339 187         1009 return $_chunk_size;
340             }
341              
342             sub _parse_max_workers {
343              
344 1139     1139   2944 my ($_max_workers) = @_;
345              
346 1139         1825 @_ = ();
347              
348 1139 50       2662 return $_max_workers unless (defined $_max_workers);
349              
350 1139 100       4659 if ($_max_workers =~ /^auto(?:$|\s*([\-\+\/\*])\s*(.+)$)/i) {
    100          
351 135         287 my ($_ncpu_ul, $_ncpu);
352              
353 135         749 $_ncpu_ul = $_ncpu = MCE::Util::get_ncpu();
354 135 50       631 $_ncpu_ul = 8 if ($_ncpu_ul > 8);
355              
356 135 100 66     929 if (defined($1) && defined($2)) {
357 48         84 local $@; $_max_workers = eval "int($_ncpu_ul $1 $2 + 0.5)"; ## no critic
  48         4902  
358 48 100 66     360 $_max_workers = 1 if (!$_max_workers || $_max_workers < 1);
359 48 50       156 $_max_workers = $_ncpu if ($_max_workers > $_ncpu);
360             }
361             else {
362 87         353 $_max_workers = $_ncpu_ul;
363             }
364             }
365             elsif ($_max_workers =~ /^([0-9.]+)%$/) {
366 54         240 my $_percent = $1 / 100;
367 54         348 my $_ncpu = MCE::Util::get_ncpu();
368              
369 54         324 $_max_workers = int($_ncpu * $_percent + 0.5);
370 54 100       162 $_max_workers = 1 if ($_max_workers < 1);
371             }
372              
373 1139         3523 return $_max_workers;
374             }
375              
376             sub _validate_number {
377              
378 81     81   347 my ($_n, $_key, $_tag) = @_;
379              
380 81 50       293 _croak("$_tag: ($_key) is not valid") if (!defined $_n);
381              
382 81         418 $_n =~ s/K\z//i; $_n =~ s/M\z//i;
  81         255  
383              
384 81 50 33     1447 if (!looks_like_number($_n) || int($_n) != $_n || $_n < 1) {
      33        
385 0         0 _croak("$_tag: ($_key) is not valid");
386             }
387              
388 81         245 return;
389             }
390              
391             1;
392              
393             __END__
394              
395             ###############################################################################
396             ## ----------------------------------------------------------------------------
397             ## Module usage.
398             ##
399             ###############################################################################
400              
401             =head1 NAME
402              
403             MCE::Core::Validation - Core validation methods for Many-Core Engine
404              
405             =head1 VERSION
406              
407             This document describes MCE::Core::Validation version 1.902
408              
409             =head1 DESCRIPTION
410              
411             This package provides validation methods used internally by the manager
412             process.
413              
414             There is no public API.
415              
416             =head1 AUTHOR
417              
418             Mario E. Roy, S<E<lt>marioeroy AT gmail DOT comE<gt>>
419              
420             =cut
421