]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/IMAPTracker.pm
imaptracker: preserve WAL journal_mode if set by user
[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) = @_;
53         my $sth = $self->{dbh}->prepare_cached(<<'');
54 INSERT OR REPLACE INTO imap_last (url, uid_validity, uid)
55 VALUES (?, ?, ?)
56
57         $self->lock_acquire;
58         my $rv = $sth->execute($self->{url}, $validity, $last);
59         $self->lock_release;
60         $rv;
61 }
62
63 sub new {
64         my ($class, $url) = @_;
65
66         # original name for compatibility with old setups:
67         my $dbname = PublicInbox::Config->config_dir() . "/imap.sqlite3";
68
69         # use the new XDG-compliant name for new setups:
70         if (!-f $dbname) {
71                 $dbname = ($ENV{XDG_DATA_HOME} //
72                         (($ENV{HOME} // '/nonexistent').'/.local/share')) .
73                         '/public-inbox/imap.sqlite3';
74         }
75         if (!-f $dbname) {
76                 require File::Path;
77                 require File::Basename;
78                 File::Path::mkpath(File::Basename::dirname($dbname));
79         }
80         my $self = bless { lock_path => "$dbname.lock", url => $url }, $class;
81         $self->lock_acquire;
82         $self->{dbh} = dbh_new($dbname);
83         $self->lock_release;
84         $self;
85 }
86
87 1;