]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/IMAPTracker.pm
nntpd: share {groups} hash with {-by_newsgroup} in Config
[public-inbox.git] / lib / PublicInbox / IMAPTracker.pm
1 # Copyright (C) 2018-2020 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3 package PublicInbox::IMAPTracker;
4 use strict;
5 use parent qw(PublicInbox::Lock);
6 use DBI;
7 use DBD::SQLite;
8 use PublicInbox::Config;
9
10 sub create_tables ($) {
11         my ($dbh) = @_;
12
13         $dbh->do(<<'');
14 CREATE TABLE IF NOT EXISTS imap_last (
15         url VARCHAR PRIMARY KEY NOT NULL,
16         uid_validity INTEGER NOT NULL,
17         uid INTEGER NOT NULL,
18         UNIQUE (url)
19 )
20
21 }
22
23 sub dbh_new ($) {
24         my ($dbname) = @_;
25         my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname", '', '', {
26                 AutoCommit => 1,
27                 RaiseError => 1,
28                 PrintError => 0,
29                 sqlite_use_immediate_transaction => 1,
30         });
31         $dbh->{sqlite_unicode} = 1;
32
33         # TRUNCATE reduces I/O compared to the default (DELETE).
34         # Allow and preserve user-overridden WAL, but don't force it.
35         my $jm = $dbh->selectrow_array('PRAGMA journal_mode');
36         $dbh->do('PRAGMA journal_mode = TRUNCATE') if $jm ne 'wal';
37
38         create_tables($dbh);
39         $dbh;
40 }
41
42 sub get_last ($) {
43         my ($self) = @_;
44         my $sth = $self->{dbh}->prepare_cached(<<'', undef, 1);
45 SELECT uid_validity, uid FROM imap_last WHERE url = ?
46
47         $sth->execute($self->{url});
48         $sth->fetchrow_array;
49 }
50
51 sub update_last ($$$) {
52         my ($self, $validity, $last_uid) = @_;
53         return unless defined $last_uid;
54         my $sth = $self->{dbh}->prepare_cached(<<'');
55 INSERT OR REPLACE INTO imap_last (url, uid_validity, uid)
56 VALUES (?, ?, ?)
57
58         $self->lock_acquire;
59         my $rv = $sth->execute($self->{url}, $validity, $last_uid);
60         $self->lock_release;
61         $rv;
62 }
63
64 sub new {
65         my ($class, $url) = @_;
66
67         # original name for compatibility with old setups:
68         my $dbname = PublicInbox::Config->config_dir() . "/imap.sqlite3";
69
70         # use the new XDG-compliant name for new setups:
71         if (!-f $dbname) {
72                 $dbname = ($ENV{XDG_DATA_HOME} //
73                         (($ENV{HOME} // '/nonexistent').'/.local/share')) .
74                         '/public-inbox/imap.sqlite3';
75         }
76         if (!-f $dbname) {
77                 require File::Path;
78                 require File::Basename;
79                 File::Path::mkpath(File::Basename::dirname($dbname));
80         }
81         my $self = bless { lock_path => "$dbname.lock", url => $url }, $class;
82         $self->lock_acquire;
83         $self->{dbh} = dbh_new($dbname);
84         $self->lock_release;
85         $self;
86 }
87
88 1;