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; |