]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Msgmap.pm
www: label sections and hopefully improve navigation
[public-inbox.git] / lib / PublicInbox / Msgmap.pm
index a1748af9be1ca4d2060446c8d1d422ecb35985ff..8fe17a9505f0db151fe8c7f8f67ff9170b54e0b9 100644 (file)
@@ -1,10 +1,15 @@
 # Copyright (C) 2015 all contributors <meta@public-inbox.org>
 # 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;