1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
| | # Copyright (C) all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
# All Locals Ever: track lei/store + externals ever used as
# long as they're on an accessible FS. Includes "lei q" --include
# and --only targets that haven't been through "lei add-external".
# Typically: ~/.cache/lei/all_locals_ever.git
package PublicInbox::LeiALE;
use v5.12;
use parent qw(PublicInbox::LeiSearch PublicInbox::Lock);
use PublicInbox::Git;
use autodie qw(close open rename seek truncate);
use PublicInbox::Import;
use PublicInbox::OnDestroy;
use PublicInbox::LeiXSearch;
use Fcntl qw(SEEK_SET);
sub _new {
my ($d) = @_;
PublicInbox::Import::init_bare($d, 'ale');
bless {
git => PublicInbox::Git->new($d),
lock_path => "$d/lei_ale.state", # dual-duty lock + state
ibxish => [], # Inbox and ExtSearch (and LeiSearch) objects
}, __PACKAGE__
}
sub new {
my ($self, $lei) = @_;
ref($self) or $self = _new($lei->cache_dir . '/all_locals_ever.git');
my $lxs = PublicInbox::LeiXSearch->new;
my $sto = $lei->_lei_store;
$lxs->prepare_external($sto->search) if $sto;
for my $loc ($lei->externals_each) { # locals only
$lxs->prepare_external($loc) if -d $loc;
}
$self->refresh_externals($lxs, $lei);
$self;
}
sub over {} # undef for xoids_for
sub overs_all { # for xoids_for (called only in lei workers?)
my ($self) = @_;
my $fgen = $PublicInbox::OnDestroy::fork_gen ;
if (($self->{fgen} // $fgen) != $fgen) {
delete($_->{over}) for @{$self->{ibxish}};
}
$self->{fgen} = $fgen;
grep(defined, map { $_->over } @{$self->{ibxish}});
}
sub refresh_externals {
my ($self, $lxs, $lei) = @_;
$self->git->cleanup;
my $lk = $self->lock_for_scope;
my $cur_lxs = ref($lxs)->new;
my $orig = PublicInbox::IO::read_all $self->{lockfh};
my $new = '';
my $old = '';
my $gone = 0;
my %seen_ibxish; # $dir => any-defined value
for my $dir (split(/\n/, $orig)) {
if (-d $dir && -r _ && $cur_lxs->prepare_external($dir)) {
$seen_ibxish{$dir} //= length($old .= "$dir\n");
} else {
++$gone;
}
}
my @ibxish = $cur_lxs->locals;
for my $x ($lxs->locals) {
my $d = $lei->canonpath_harder($x->{inboxdir} // $x->{topdir});
$seen_ibxish{$d} //= do {
$new .= "$d\n";
push @ibxish, $x;
};
}
if ($new ne '' || $gone) {
$self->{lockfh}->autoflush(1);
if ($gone) {
seek($self->{lockfh}, 0, SEEK_SET);
truncate($self->{lockfh}, 0);
} else {
$old = '';
}
print { $self->{lockfh} } $old, $new or die "print: $!";
}
$new = '';
my $f = $self->git->{git_dir}.'/objects/info/alternates';
$old = PublicInbox::IO::try_cat $f;
for my $x (@ibxish) {
$new .= $lei->canonpath_harder($x->git->{git_dir})."/objects\n";
}
$self->{ibxish} = \@ibxish;
return if $old eq $new;
# this needs to be atomic since child processes may start
# git-cat-file at any time
my $tmp = "$f.$$.tmp";
open my $fh, '>', $tmp;
print $fh $new;
close $fh;
rename($tmp, $f)
}
1;
|