]> Sergey Matveev's repositories - public-inbox.git/commitdiff
index+xcpdb: support --no-sync flag
authorEric Wong <e@yhbt.net>
Fri, 24 Jul 2020 05:56:02 +0000 (05:56 +0000)
committerEric Wong <e@yhbt.net>
Sat, 25 Jul 2020 20:48:18 +0000 (20:48 +0000)
This allows us to speed up indexing operations to SQLite
and Xapian.

Unfortunately, it doesn't affect operations using
`xapian-compact' and the compactor API, since that doesn't seem
to support Xapian::DB_NO_SYNC, yet.

Documentation/public-inbox-index.pod
Documentation/public-inbox-xcpdb.pod
lib/PublicInbox/Msgmap.pm
lib/PublicInbox/Over.pm
lib/PublicInbox/OverIdx.pm
lib/PublicInbox/SearchIdx.pm
lib/PublicInbox/V2Writable.pm
lib/PublicInbox/Xapcmd.pm
script/public-inbox-index
script/public-inbox-xcpdb

index 08f2fbf453228db0ac7bb917d7a9f5642e0a8c6a..aeb1b3a39fbfaf9c4da3144c3f18b98014774895 100644 (file)
@@ -113,6 +113,13 @@ below.
 
 Available in public-inbox 1.6.0 (PENDING).
 
+=item --no-sync
+
+Disables L<fsync(2)> and L<fdatasync(2)> operations on SQLite
+and Xapian.  This is only effective with Xapian 1.4+.
+
+Available in public-inbox 1.6.0 (PENDING).
+
 =back
 
 =head1 FILES
index 149c8f78c738fc60a18e1f9def1e295d745f65eb..7fe1e5fe2cc1f53aaa7b8c21b5c097016c987ccb 100644 (file)
@@ -45,6 +45,12 @@ too many shards given the capabilities of the current hardware.
 These options are passed directly to L<xapian-compact(1)> when
 used with C<--compact>.
 
+=item --no-sync
+
+Disable L<fsync(2)> and L<fdatasync(2)>.
+
+Available in public-inbox 1.6.0 (PENDING).
+
 =back
 
 =head1 ENVIRONMENT
index 9d2ef0dc5455f2c239ad54d283fe24a272d23bdc..839ddf7cadbbec6b85dde59de1334b55b5a721c7 100644 (file)
@@ -32,12 +32,11 @@ sub new_file {
        my $self = bless { filename => $f }, $class;
        my $dbh = $self->{dbh} = PublicInbox::Over::dbh_new($self, $rw);
        if ($rw) {
-               create_tables($dbh);
-
                # TRUNCATE reduces I/O compared to the default (DELETE)
                $dbh->do('PRAGMA journal_mode = TRUNCATE');
 
                $dbh->begin_work;
+               create_tables($dbh);
                $self->created_at(time) unless $self->created_at;
 
                my $max = $self->max // 0;
@@ -51,12 +50,17 @@ sub new_file {
 sub tmp_clone {
        my ($self) = @_;
        my ($fh, $fn) = tempfile('msgmap-XXXXXXXX', EXLOCK => 0, TMPDIR => 1);
-       $self->{dbh}->sqlite_backup_to_file($fn);
-       my $tmp = ref($self)->new_file($fn, 1);
-       $tmp->{dbh}->do('PRAGMA synchronous = OFF');
-       $tmp->{dbh}->do('PRAGMA journal_mode = MEMORY');
+       my $tmp;
+       if ($self->{dbh}->can('sqlite_backup_to_dbh')) {
+               $tmp = ref($self)->new_file($fn, 2);
+               $tmp->{dbh}->do('PRAGMA journal_mode = MEMORY');
+               $self->{dbh}->sqlite_backup_to_dbh($tmp->{dbh});
+       } else { # DBD::SQLite <= 1.61_01
+               $self->{dbh}->sqlite_backup_to_file($fn);
+               $tmp = ref($self)->new_file($fn, 2);
+               $tmp->{dbh}->do('PRAGMA journal_mode = MEMORY');
+       }
        $tmp->{pid} = $$;
-       close $fh or die "failed to close $fn: $!";
        $tmp;
 }
 
@@ -241,8 +245,7 @@ sub atfork_parent {
        $self->{pid} or die 'BUG: not a temporary clone';
        $self->{dbh} and die 'BUG: tmp_clone dbh not prepared for parent';
        defined($self->{filename}) or die 'BUG: {filename} not defined';
-       my $dbh = $self->{dbh} = PublicInbox::Over::dbh_new($self, 1);
-       $dbh->do('PRAGMA synchronous = OFF');
+       $self->{dbh} = PublicInbox::Over::dbh_new($self, 2);
 }
 
 sub atfork_prepare {
index e3f264564434ef477fd90c25de29b8450bebb27c..f32743c05a8a461baf0c4f5a52c983d5fecd25af 100644 (file)
@@ -40,6 +40,7 @@ sub dbh_new {
                $st = pack('dd', $st[0], $st[1]);
        } while ($st ne $self->{st} && $tries++ < 3);
        warn "W: $f: .st_dev, .st_ino unstable\n" if $st ne $self->{st};
+       $dbh->do('PRAGMA synchronous = OFF') if ($rw // 0) > 1;
        $dbh;
 }
 
index c57be7243a59356a3c18691f318207b0e062ca91..fcb450794fc2c05bffab9a49a330b686d22f1913 100644 (file)
@@ -21,7 +21,7 @@ use Carp qw(croak);
 
 sub dbh_new {
        my ($self) = @_;
-       my $dbh = $self->SUPER::dbh_new(1);
+       my $dbh = $self->SUPER::dbh_new($self->{-no_sync} ? 2 : 1);
 
        # TRUNCATE reduces I/O compared to the default (DELETE)
        # We do not use WAL since we're optimized for read-only ops,
index c57a7e1647c11e61d7f45aa23dbe2fd524b439f0..764257432518d9f7f8558828970bc5e432c0bc27 100644 (file)
@@ -23,6 +23,7 @@ use PublicInbox::Git qw(git_unquote);
 use PublicInbox::MsgTime qw(msg_timestamp msg_datestamp);
 my $X = \%PublicInbox::Search::X;
 my ($DB_CREATE_OR_OPEN, $DB_OPEN);
+our $DB_NO_SYNC = 0;
 our $BATCH_BYTES = defined($ENV{XAPIAN_FLUSH_THRESHOLD}) ?
                        0x7fffffff : 1_000_000;
 use constant DEBUG => !!$ENV{DEBUG};
@@ -67,6 +68,7 @@ sub new {
                $self->{lock_path} = "$inboxdir/ssoma.lock";
                my $dir = $self->xdir;
                $self->{over} = PublicInbox::OverIdx->new("$dir/over.sqlite3");
+               $self->{over}->{-no_sync} = 1 if $ibx->{-no_sync};
                $self->{index_max_size} = $ibx->{index_max_size};
        } elsif ($version == 2) {
                defined $shard or die "shard is required for v2\n";
@@ -103,6 +105,9 @@ sub load_xapian_writable () {
        *sortable_serialise = $xap.'::sortable_serialise';
        $DB_CREATE_OR_OPEN = eval($xap.'::DB_CREATE_OR_OPEN()');
        $DB_OPEN = eval($xap.'::DB_OPEN()');
+       my $ver = (eval($xap.'::major_version()') << 16) |
+               (eval($xap.'::minor_version()') << 8);
+       $DB_NO_SYNC = 0x4 if $ver >= 0x10400;
        1;
 }
 
@@ -126,6 +131,7 @@ sub idx_acquire {
                }
        }
        return unless defined $flag;
+       $flag |= $DB_NO_SYNC if $self->{ibx}->{-no_sync};
        my $xdb = eval { ($X->{WritableDatabase})->new($dir, $flag) };
        if ($@) {
                die "Failed opening $dir: ", $@;
@@ -377,7 +383,8 @@ sub _msgmap_init ($) {
        die "BUG: _msgmap_init is only for v1\n" if $self->{ibx_ver} != 1;
        $self->{mm} //= eval {
                require PublicInbox::Msgmap;
-               PublicInbox::Msgmap->new($self->{ibx}->{inboxdir}, 1);
+               my $rw = $self->{ibx}->{-no_sync} ? 2 : 1;
+               PublicInbox::Msgmap->new($self->{ibx}->{inboxdir}, $rw);
        };
 }
 
index 13c1ad6f8c4815e6781602633163ccc79ee8812d..3dc200956679916053181a8de400f886026ab641 100644 (file)
@@ -116,12 +116,13 @@ sub new {
                total_bytes => 0,
                current_info => '',
                xpfx => $xpfx,
-               over => PublicInbox::OverIdx->new("$xpfx/over.sqlite3", 1),
+               over => PublicInbox::OverIdx->new("$xpfx/over.sqlite3"),
                lock_path => "$dir/inbox.lock",
                # limit each git repo (epoch) to 1GB or so
                rotate_bytes => int((1024 * 1024 * 1024) / $PACKING_FACTOR),
                last_commit => [], # git epoch -> commit
        };
+       $self->{over}->{-no_sync} = 1 if $v2ibx->{-no_sync};
        $self->{shards} = count_shards($self) || nproc_shards($creat);
        $self->{index_max_size} = $v2ibx->{index_max_size};
        bless $self, $class;
@@ -293,7 +294,8 @@ sub _idx_init { # with_umask callback
        # Now that all subprocesses are up, we can open the FDs
        # for SQLite:
        my $mm = $self->{mm} = PublicInbox::Msgmap->new_file(
-               "$self->{ibx}->{inboxdir}/msgmap.sqlite3", 1);
+                               "$self->{ibx}->{inboxdir}/msgmap.sqlite3",
+                               $self->{ibx}->{-no_sync} ? 2 : 1);
        $mm->{dbh}->begin_work;
 }
 
index 4ee3fc79195d5f59e3ff18b29761dd875675fdf6..d6c069d75efe25535579fe46505cabee1b245290 100644 (file)
@@ -412,10 +412,11 @@ sub cpdb ($$) {
 
        # like copydatabase(1), be sure we don't overwrite anything in case
        # of other bugs:
-       my $creat = eval($PublicInbox::Search::Xap.'::DB_CREATE()');
+       my $flag = eval($PublicInbox::Search::Xap.'::DB_CREATE()');
        die if $@;
        my $XapianWritableDatabase = $PublicInbox::Search::X{WritableDatabase};
-       my $dst = $XapianWritableDatabase->new($tmp, $creat);
+       $flag |= $PublicInbox::SearchIdx::DB_NO_SYNC if !$opt->{sync};
+       my $dst = $XapianWritableDatabase->new($tmp, $flag);
        my $pr = $opt->{-progress};
        my $pfx = $opt->{-progress_pfx} = progress_pfx($new);
        my $pr_data = { pr => $pr, pfx => $pfx, nr => 0 } if $pr;
index 2e1934b0833110d58ca0b2ccaba47cd6249419ff..d5c7cae2b9f53d0ca5c797bb60c5ec4cf7e2b282 100755 (executable)
@@ -14,8 +14,8 @@ PublicInbox::Admin::require_or_die('-index');
 use PublicInbox::Xapcmd;
 
 my $compact_opt;
-my $opt = { quiet => -1, compact => 0, maxsize => undef };
-GetOptions($opt, qw(verbose|v+ reindex rethread compact|c+ jobs|j=i prune
+my $opt = { quiet => -1, compact => 0, maxsize => undef, sync => 1 };
+GetOptions($opt, qw(verbose|v+ reindex rethread compact|c+ jobs|j=i prune sync!
                indexlevel|L=s maxsize|max-size=s batchsize|batch-size=s))
        or die "bad command-line args\n$usage";
 die "--jobs must be >= 0\n" if defined $opt->{jobs} && $opt->{jobs} < 0;
@@ -59,6 +59,7 @@ for my $ibx (@ibxs) {
        if ($opt->{compact} >= 2) {
                PublicInbox::Xapcmd::run($ibx, 'compact', $compact_opt);
        }
+       $ibx->{-no_sync} = 1 if !$opt->{sync};
        PublicInbox::Admin::index_inbox($ibx, undef, $opt);
        PublicInbox::Xapcmd::run($ibx, 'compact', $compact_opt) if $compact_opt;
 }
index 2b9f032c5c01880efa6a8daa7d986bcea792272b..fcd9614884b6c0cd5ccb1ee8c4258076c6979352 100755 (executable)
@@ -8,8 +8,8 @@ use PublicInbox::Xapcmd;
 use PublicInbox::Admin;
 PublicInbox::Admin::require_or_die('-search');
 my $usage = "Usage: public-inbox-xcpdb [--compact] INBOX_DIR\n";
-my $opt = {};
-my @opt = (qw(compact reshard|R=i), @PublicInbox::Xapcmd::COMPACT_OPT);
+my $opt = { sync => 1 };
+my @opt = (qw(sync! compact reshard|R=i), @PublicInbox::Xapcmd::COMPACT_OPT);
 GetOptions($opt, @opt) or die "bad command-line args\n$usage";
 my @ibxs = PublicInbox::Admin::resolve_inboxes(\@ARGV) or die $usage;
 foreach (@ibxs) {