| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package App::dategrep::Iterator::File; |
|
2
|
9
|
|
|
9
|
|
31
|
use strict; |
|
|
9
|
|
|
|
|
12
|
|
|
|
9
|
|
|
|
|
200
|
|
|
3
|
9
|
|
|
9
|
|
27
|
use warnings; |
|
|
9
|
|
|
|
|
11
|
|
|
|
9
|
|
|
|
|
186
|
|
|
4
|
9
|
|
|
9
|
|
27
|
use Fcntl ":seek"; |
|
|
9
|
|
|
|
|
7
|
|
|
|
9
|
|
|
|
|
1034
|
|
|
5
|
9
|
|
|
9
|
|
3770
|
use File::stat; |
|
|
9
|
|
|
|
|
41385
|
|
|
|
9
|
|
|
|
|
33
|
|
|
6
|
9
|
|
|
9
|
|
459
|
use Moo; |
|
|
9
|
|
|
|
|
11
|
|
|
|
9
|
|
|
|
|
46
|
|
|
7
|
9
|
|
|
9
|
|
5528
|
use FileHandle; |
|
|
9
|
|
|
|
|
5724
|
|
|
|
9
|
|
|
|
|
34
|
|
|
8
|
|
|
|
|
|
|
extends 'App::dategrep::Iterator'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
has filename => ( is => 'ro', required => 1 ); |
|
11
|
|
|
|
|
|
|
has blocksize => ( is => 'lazy' ); |
|
12
|
|
|
|
|
|
|
|
|
13
|
3
|
|
|
3
|
0
|
11
|
sub can_seek { 1 } |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub _build_blocksize { |
|
16
|
24
|
|
|
24
|
|
2271
|
my $self = shift; |
|
17
|
24
|
|
50
|
|
|
355
|
return stat( $self->fh )->blksize || 8192; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub _build_fh { |
|
21
|
28
|
|
|
28
|
|
2728
|
my $self = shift; |
|
22
|
28
|
|
|
|
|
73
|
my $filename = $self->filename; |
|
23
|
28
|
100
|
|
|
|
1054
|
open( my $fh, '<', $filename ) or die "Can't open $filename: $!\n"; |
|
24
|
27
|
|
|
|
|
104
|
return $fh; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub seek { |
|
28
|
28
|
|
|
28
|
0
|
37
|
my $self = shift; |
|
29
|
|
|
|
|
|
|
|
|
30
|
28
|
|
|
|
|
184
|
my $min = $self->search( $self->start ); |
|
31
|
|
|
|
|
|
|
|
|
32
|
26
|
100
|
|
|
|
58
|
if ( not defined $min ) { |
|
33
|
2
|
|
|
|
|
8
|
$self->eof(1); |
|
34
|
2
|
|
|
|
|
34
|
return; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
24
|
|
|
|
|
600
|
my $line = $self->fh->getline; |
|
38
|
24
|
|
|
|
|
962
|
my ( $date, $error ) = $self->to_epoch($line); |
|
39
|
|
|
|
|
|
|
|
|
40
|
24
|
100
|
|
|
|
4467
|
if ( $date >= $self->end ) { |
|
41
|
1
|
|
|
|
|
4
|
$self->eof(1); |
|
42
|
1
|
|
|
|
|
19
|
return; |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
23
|
|
|
|
|
121
|
$self->next_line($line); |
|
46
|
23
|
|
|
|
|
61
|
$self->next_date($date); |
|
47
|
23
|
|
|
|
|
480
|
return; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub byte_offsets { |
|
51
|
2
|
|
|
2
|
0
|
3
|
my $self = shift; |
|
52
|
2
|
|
|
|
|
5
|
my $tell_beg = $self->search( $self->start ); |
|
53
|
|
|
|
|
|
|
|
|
54
|
2
|
50
|
|
|
|
6
|
if ( defined $tell_beg ) { |
|
55
|
2
|
|
|
|
|
7
|
my $tell_end = $self->search( $self->end, $tell_beg ); |
|
56
|
2
|
|
|
|
|
6
|
return $tell_beg, $tell_end; |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# return for empty file |
|
60
|
0
|
|
|
|
|
0
|
return 0, -1; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub search { |
|
64
|
35
|
|
|
35
|
0
|
58
|
my $self = shift; |
|
65
|
35
|
|
|
|
|
50
|
my ( $key, $min_byte ) = @_; |
|
66
|
35
|
|
|
|
|
478
|
my $fh = $self->fh; |
|
67
|
|
|
|
|
|
|
|
|
68
|
34
|
|
|
|
|
148
|
my $size = stat($fh)->size; |
|
69
|
34
|
|
|
|
|
4732
|
my $blksize = $self->blocksize; |
|
70
|
34
|
|
|
|
|
2504
|
my $multiline = $self->multiline; |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# find the right block |
|
73
|
34
|
|
|
|
|
97
|
my ( $min, $max, $mid ) = ( 0, int( $size / $blksize ) ); |
|
74
|
|
|
|
|
|
|
|
|
75
|
34
|
100
|
|
|
|
78
|
if ( defined $min_byte ) { |
|
76
|
5
|
|
|
|
|
9
|
$min = int( $min_byte / $blksize ); |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
34
|
|
|
|
|
92
|
BLOCK: while ( $max - $min > 1 ) { |
|
80
|
9
|
|
|
|
|
15
|
$mid = int( ( $max + $min ) / 2 ); |
|
81
|
9
|
50
|
|
|
|
35
|
$fh->seek( $mid * $blksize, SEEK_SET ) or return; |
|
82
|
9
|
50
|
|
|
|
260
|
$fh->getline if $mid; # probably a partial line |
|
83
|
9
|
|
|
|
|
252
|
LINE: while (1) { |
|
84
|
12
|
|
|
|
|
211
|
my $line = $fh->getline(); |
|
85
|
12
|
100
|
|
|
|
231
|
if ( !$line ) { |
|
86
|
|
|
|
|
|
|
## This can happen if line size is way bigger than blocksize |
|
87
|
3
|
|
|
|
|
6
|
last BLOCK; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
9
|
|
|
|
|
28
|
my ($epoch) = $self->to_epoch($line); |
|
90
|
9
|
100
|
|
|
|
1285
|
if ( !$epoch ) { |
|
91
|
3
|
50
|
33
|
|
|
12
|
next LINE if $multiline || $self->skip_unparsable; |
|
92
|
0
|
|
|
|
|
0
|
die "No date found in line $line"; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
6
|
100
|
|
|
|
28
|
$epoch < $key |
|
96
|
|
|
|
|
|
|
? $min = int( ( $fh->tell - length($line) ) / $blksize ) |
|
97
|
|
|
|
|
|
|
: $max = $mid; |
|
98
|
|
|
|
|
|
|
|
|
99
|
6
|
|
|
|
|
31
|
next BLOCK; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# find the right line |
|
104
|
34
|
|
|
|
|
35
|
$min *= $blksize; |
|
105
|
34
|
50
|
|
|
|
173
|
$fh->seek( $min, SEEK_SET ) or return; |
|
106
|
34
|
100
|
|
|
|
316
|
$fh->getline if $min; # probably a partial line |
|
107
|
34
|
|
|
|
|
96
|
for ( ; ; ) { |
|
108
|
66
|
|
|
|
|
192
|
$min = $fh->tell; |
|
109
|
66
|
100
|
|
|
|
1443
|
defined( my $line = $fh->getline ) or last; |
|
110
|
61
|
|
|
|
|
1584
|
my ($epoch) = $self->to_epoch($line); |
|
111
|
61
|
100
|
|
|
|
10373
|
if ( !$epoch ) { |
|
112
|
9
|
100
|
66
|
|
|
40
|
next if $multiline || $self->skip_unparsable; |
|
113
|
1
|
|
|
|
|
41
|
die "No date found in line $line"; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
52
|
100
|
|
|
|
124
|
if ( $epoch >= $key ) { |
|
116
|
28
|
|
|
|
|
92
|
$fh->seek( $min, SEEK_SET ); |
|
117
|
28
|
|
|
|
|
183
|
return $min; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
} |
|
120
|
5
|
|
|
|
|
144
|
return; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
1; |