From f87d737e0f2c418c487f9de60b9cf7948de53013 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Feb 2022 13:17:51 -0600 Subject: [PATCH] feat: newly-added seeds skip the full verify step (#2626) * feat: newly-added seeds skip the full verify step This has been a much-requested feature but has also been contentious because I want to ensure that Transmission never transmits unverified data. See the GH pull request for context on how this works. --- libtransmission/completion.cc | 10 ++++++++ libtransmission/completion.h | 2 ++ libtransmission/torrent.cc | 48 +++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/libtransmission/completion.cc b/libtransmission/completion.cc index b78139e51..1efd7bc36 100644 --- a/libtransmission/completion.cc +++ b/libtransmission/completion.cc @@ -167,6 +167,16 @@ void tr_completion::setBlocks(tr_bitfield blocks) has_valid_.reset(); } +void tr_completion::setHasAll() +{ + auto const total_size = block_info_->totalSize(); + + blocks_.setHasAll(); + size_now_ = total_size; + size_when_done_ = total_size; + has_valid_ = total_size; +} + void tr_completion::addPiece(tr_piece_index_t piece) { auto const [begin, end] = block_info_->blockSpanForPiece(piece); diff --git a/libtransmission/completion.h b/libtransmission/completion.h index ed539d38a..522163be0 100644 --- a/libtransmission/completion.h +++ b/libtransmission/completion.h @@ -118,6 +118,8 @@ struct tr_completion } } + void setHasAll(); + void setBlocks(tr_bitfield blocks); void invalidateSizeWhenDone() diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index ce267d2f3..b47913cfe 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -628,6 +628,49 @@ static bool setLocalErrorIfFilesDisappeared(tr_torrent* tor) return disappeared; } +/** + * Sniff out newly-added seeds so that they can skip the verify step + */ +static bool isNewTorrentASeed(tr_torrent* tor) +{ + if (!tor->hasMetadata()) + { + return false; + } + + auto filename_buf = std::string{}; + for (tr_file_index_t i = 0, n = tor->fileCount(); i < n; ++i) + { + // it's not a new seed if a file is missing + auto const found = tor->findFile(filename_buf, i); + if (!found) + { + return false; + } + + // it's not a new seed if a file is partial + if (tr_strvEndsWith(found->filename, ".part"sv)) + { + return false; + } + + // it's not a new seed if a file size is wrong + if (found->size != tor->fileSize(i)) + { + return false; + } + + // it's not a new seed if it was modified after it was added + if (found->last_modified_at >= tor->addedDate) + { + return false; + } + } + + // check the first piece + return tor->ensurePieceIsChecked(0); +} + static void refreshCurrentDir(tr_torrent* tor); static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) @@ -752,6 +795,11 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) tor->prefetchMagnetMetadata = true; tr_torrentStartNow(tor); } + else if (isNewTorrentASeed(tor)) + { + tor->completion.setHasAll(); + tor->recheckCompleteness(); + } else { tor->startAfterVerify = doStart;