+sub cpdb_retryable ($$) {
+ my ($src, $err) = @_;
+ if (ref($err) eq 'Search::Xapian::DatabaseModifiedError') {
+ warn "$err, reopening and retrying\n";
+ $src->reopen;
+ return 1;
+ }
+ die $err if $err;
+ 0;
+}
+
+sub cpdb {
+ my ($args, $env, $opt) = @_;
+ my ($old, $new) = @$args;
+ my $src = Search::Xapian::Database->new($old);
+
+ # like copydatabase(1), be sure we don't overwrite anything in case
+ # of other bugs:
+ my $creat = Search::Xapian::DB_CREATE();
+ my $dst = Search::Xapian::WritableDatabase->new($new, $creat);
+ my ($it, $end);
+
+ do {
+ eval {
+ # update the only metadata key for v1:
+ my $lc = $src->get_metadata('last_commit');
+ $dst->set_metadata('last_commit', $lc) if $lc;
+
+ $it = $src->postlist_begin('');
+ $end = $src->postlist_end('');
+ };
+ } while (cpdb_retryable($src, $@));
+
+ do {
+ eval {
+ while ($it != $end) {
+ my $docid = $it->get_docid;
+ my $doc = $src->get_document($docid);
+ $dst->replace_document($docid, $doc);
+ $it->inc;
+ }
+
+ # unlike copydatabase(1), we don't copy spelling
+ # and synonym data (or other user metadata) since
+ # the Perl APIs don't expose iterators for them
+ # (and public-inbox does not use those features)
+ };
+ } while (cpdb_retryable($src, $@));
+}
+