# Copyright (C) all contributors # License: AGPL-3.0+ # mocks Xapian::Mset and allows slow queries from blocking the event loop package PublicInbox::XhcMset; use v5.12; use parent qw(PublicInbox::DS); use PublicInbox::XhcMsetIterator; use PublicInbox::Syscall qw(EPOLLIN EPOLLONESHOT); sub event_step { my ($self) = @_; my ($cb, @args) = @{delete $self->{cb_args} // return}; my $rd = $self->{sock}; eval { my $hdr = <$rd> // die "E: reading mset header: $!"; for (split /\s+/, $hdr) { # read mset.size + estimated_matches my ($k, $v) = split /=/, $_, 2; $k =~ s/\A[^\.]*\.//; # s/(mset)?\./ $self->{$k} = $v; } my $size = $self->{size} // die "E: bad xhc header: `$hdr'"; my @it = map { PublicInbox::XhcMsetIterator::make($_) } <$rd>; $self->{items} = \@it; scalar(@it) == $size or die 'E: got ',scalar(@it),", expected mset.size=$size"; }; my $err = $@; $self->close; eval { $cb->(@args, $self, $err) }; warn "E: $@\n" if $@; } sub maybe_new { my (undef, $rd, $srch, @cb_args) = @_; my $self = bless { cb_args => \@cb_args, srch => $srch }, __PACKAGE__; if ($PublicInbox::DS::in_loop) { # async $self->SUPER::new($rd, EPOLLIN|EPOLLONESHOT); } else { # synchronous $self->{sock} = $rd; event_step($self); undef; } } eval(join('', map { "sub $_ { \$_[0]->{$_} }\n" } qw(size get_matches_estimated))); sub items { @{$_[0]->{items}} } 1;