X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FMsgmap.pm;h=8fe17a9505f0db151fe8c7f8f67ff9170b54e0b9;hb=803914775816f7de5485fa397bad64e1bd404381;hp=a1748af9be1ca4d2060446c8d1d422ecb35985ff;hpb=a94b930f4804cd2019b69e1371753810e6e97ff8;p=public-inbox.git diff --git a/lib/PublicInbox/Msgmap.pm b/lib/PublicInbox/Msgmap.pm index a1748af9..8fe17a95 100644 --- a/lib/PublicInbox/Msgmap.pm +++ b/lib/PublicInbox/Msgmap.pm @@ -1,10 +1,15 @@ # Copyright (C) 2015 all contributors # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt) -# bidirectional Message-ID <-> Article Number mapping + +# bidirectional Message-ID <-> Article Number mapping for the NNTP +# and web interfaces. This is required for implementing stable article +# numbers for NNTP and allows prefix lookups for partial Message-IDs +# in case URLs get truncated from copy-n-paste errors by users. +# +# This is maintained by ::SearchIdx package PublicInbox::Msgmap; use strict; use warnings; -use fields qw(dbh mid_insert mid_for num_for); use DBI; use DBD::SQLite; @@ -20,46 +25,58 @@ sub new { AutoCommit => 1, RaiseError => 1, PrintError => 0, + ReadOnly => !$writable, sqlite_use_immediate_transaction => 1, }); $dbh->do('PRAGMA case_sensitive_like = ON'); + my $self = bless { dbh => $dbh }, $class; - $writable and create_tables($dbh); - my $self = fields::new($class); - $self->{dbh} = $dbh; + if ($writable) { + create_tables($dbh); + $self->created_at(time) unless $self->created_at; + } $self; } -# accessor -sub last_commit { - my ($self, $commit) = @_; - my $dbh = $self->{dbh}; - my $prev; +sub meta_accessor { + my ($self, $key, $value) = @_; use constant { - key => 'last_commit', meta_select => 'SELECT val FROM meta WHERE key = ? LIMIT 1', meta_update => 'UPDATE meta SET val = ? WHERE key = ? LIMIT 1', meta_insert => 'INSERT INTO meta (key,val) VALUES (?,?)', }; - defined $commit or - return $dbh->selectrow_array(meta_select, undef, key); + my $dbh = $self->{dbh}; + my $prev; + defined $value or + return $dbh->selectrow_array(meta_select, undef, $key); $dbh->begin_work; eval { - $prev = $dbh->selectrow_array(meta_select, undef, key); + $prev = $dbh->selectrow_array(meta_select, undef, $key); if (defined $prev) { - $dbh->do(meta_update, undef, $commit, key); + $dbh->do(meta_update, undef, $value, $key); } else { - $dbh->do(meta_insert, undef, key, $commit); + $dbh->do(meta_insert, undef, $key, $value); } $dbh->commit; }; - return $prev unless $@; + my $err = $@; + return $prev unless $err; $dbh->rollback; - die $@; + die $err; +} + +sub last_commit { + my ($self, $commit) = @_; + $self->meta_accessor('last_commit', $commit); +} + +sub created_at { + my ($self, $second) = @_; + $self->meta_accessor('created_at', $second); } sub mid_insert { @@ -72,10 +89,10 @@ sub mid_insert { $dbh->last_insert_id(undef, undef, 'msgmap', 'num'); } -use constant MID_FOR => 'SELECT mid FROM msgmap WHERE num = ? LIMIT 1'; sub mid_for { my ($self, $num) = @_; my $dbh = $self->{dbh}; + use constant MID_FOR => 'SELECT mid FROM msgmap WHERE num = ? LIMIT 1'; my $sth = $self->{mid_for} ||= $dbh->prepare(MID_FOR); $sth->bind_param(1, $num); $sth->execute; @@ -92,6 +109,15 @@ sub num_for { $sth->fetchrow_array; } +sub minmax { + my ($self) = @_; + my $dbh = $self->{dbh}; + use constant NUM_MINMAX => 'SELECT MIN(num),MAX(num) FROM msgmap'; + my $sth = $self->{num_minmax} ||= $dbh->prepare(NUM_MINMAX); + $sth->execute; + $sth->fetchrow_array; +} + sub mid_prefixes { my ($self, $pfx, $limit) = @_; @@ -134,4 +160,17 @@ sub create_tables { 'val VARCHAR(255) NOT NULL)'); } +sub id_batch { + my ($self, $num, $cb) = @_; + my $dbh = $self->{dbh}; + my $sth = $dbh->prepare('SELECT num FROM msgmap WHERE num > ? '. + 'ORDER BY num ASC LIMIT 1000'); + $sth->execute($num); + my $ary = $sth->fetchall_arrayref; + @$ary = map { $_->[0] } @$ary; + my $nr = scalar @$ary; + $cb->($ary) if $nr; + $nr; +} + 1;