]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/GzipFilter.pm
gzipfilter: lazy allocate the deflate context
[public-inbox.git] / lib / PublicInbox / GzipFilter.pm
1 # Copyright (C) 2020 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3
4 # Qspawn filter
5 package PublicInbox::GzipFilter;
6 use strict;
7 use bytes (); # length
8 use Compress::Raw::Zlib qw(Z_FINISH Z_OK);
9 my %OPT = (-WindowBits => 15 + 16, -AppendOutput => 1);
10
11 sub new { bless {}, shift }
12
13 # for Qspawn if using $env->{'pi-httpd.async'}
14 sub attach {
15         my ($self, $fh) = @_;
16         $self->{fh} = $fh;
17         $self
18 }
19
20 # for GetlineBody (via Qspawn) when NOT using $env->{'pi-httpd.async'}
21 sub translate ($$) {
22         my $self = $_[0];
23
24         # allocate the zlib context lazily here, instead of in ->new.
25         # Deflate contexts are memory-intensive and this object may
26         # be sitting in the Qspawn limiter queue for a while.
27         my $gz = $self->{gz} ||= do {
28                 my ($g, $err) = Compress::Raw::Zlib::Deflate->new(%OPT);
29                 $err == Z_OK or die "Deflate->new failed: $err";
30                 $g;
31         };
32         my $zbuf = delete($self->{zbuf});
33         if (defined $_[1]) { # my $buf = $_[1];
34                 my $err = $self->{gz}->deflate($_[1], $zbuf);
35                 die "gzip->deflate: $err" if $err != Z_OK;
36                 return $zbuf if length($zbuf) >= 8192;
37
38                 $self->{zbuf} = $zbuf;
39                 '';
40         } else { # undef == EOF
41                 my $err = $self->{gz}->flush($zbuf, Z_FINISH);
42                 die "gzip->flush: $err" if $err != Z_OK;
43                 $zbuf;
44         }
45 }
46
47 sub write {
48         # my $ret = bytes::length($_[1]); # XXX does anybody care?
49         $_[0]->{fh}->write(translate($_[0], $_[1]));
50 }
51
52 sub close {
53         my ($self) = @_;
54         my $fh = delete $self->{fh};
55         $fh->write(translate($self, undef));
56         $fh->close;
57 }
58
59 1;