]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/IdxStack.pm
b43b8064e5e2717e41d229193a83db117ab27e6a
[public-inbox.git] / lib / PublicInbox / IdxStack.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 # temporary stack for public-inbox-index
5 package PublicInbox::IdxStack;
6 use v5.10.1;
7 use strict;
8 use Fcntl qw(:seek);
9 use constant FMT => eval { pack('Q', 1) } ? 'A1QQH*' : 'A1IIH*';
10
11 # start off in write-only mode
12 sub new {
13         open(my $io, '+>', undef) or die "open: $!";
14         bless { wr => $io, latest_cmt => $_[1] }, __PACKAGE__
15 }
16
17 # file_char = [a|m]
18 sub push_rec {
19         my ($self, $file_char, $at, $ct, $blob_oid) = @_;
20         my $rec = pack(FMT, $file_char, $at, $ct, $blob_oid);
21         $self->{rec_size} //= length($rec);
22         print { $self->{wr} } $rec or die "print: $!";
23         $self->{tot_size} += length($rec);
24 }
25
26 sub num_records {
27         my ($self) = @_;
28         $self->{rec_size} ? $self->{tot_size} / $self->{rec_size} : 0;
29 }
30
31 # switch into read-only mode and returns self
32 sub read_prepare {
33         my ($self) = @_;
34         my $io = $self->{rd} = delete($self->{wr});
35         $io->flush or die "flush: $!";
36         $self;
37 }
38
39 sub pop_rec {
40         my ($self) = @_;
41         my $sz = $self->{rec_size} or return;
42         my $rec_pos = $self->{tot_size} -= $sz;
43         return if $rec_pos < 0;
44         my $io = $self->{rd};
45         seek($io, $rec_pos, SEEK_SET) or die "seek: $!";
46         my $r = read($io, my $buf, $sz);
47         defined($r) or die "read: $!";
48         $r == $sz or die "read($r != $sz)";
49         unpack(FMT, $buf);
50 }
51
52 1;