perf: avoid excess filesystem checks (#2786)

This commit is contained in:
Charles Kerr 2022-03-18 16:31:25 -05:00 committed by GitHub
parent 7b837bca1f
commit 44e30bf092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 25 deletions

View File

@ -122,11 +122,11 @@ bool tr_address_from_string(tr_address* dst, std::string_view src)
return tr_address_from_string(dst, std::data(buf));
}
std::optional<tr_address> tr_address::from_string(std::string_view str)
std::optional<tr_address> tr_address::from_string(std::string_view address_str)
{
auto addr = tr_address{};
if (!tr_address_from_string(&addr, str))
if (!tr_address_from_string(&addr, address_str))
{
return {};
}

View File

@ -44,9 +44,9 @@ public:
{
return blockInfo().blockCount();
}
[[nodiscard]] auto byteLoc(uint64_t byte) const
[[nodiscard]] auto byteLoc(uint64_t nth_byte) const
{
return blockInfo().byteLoc(byte);
return blockInfo().byteLoc(nth_byte);
}
[[nodiscard]] auto blockLoc(tr_block_index_t block) const
{

View File

@ -556,7 +556,16 @@ static void onTrackerResponse(tr_torrent* tor, tr_tracker_event const* event, vo
****
***/
static void torrentStart(tr_torrent* tor, bool bypass_queue);
struct torrent_start_opts
{
bool bypass_queue = false;
// true or false if we know whether or not local data exists,
// or unset if we don't know and need to check for ourselves
std::optional<bool> has_local_data;
};
static void torrentStart(tr_torrent* tor, torrent_start_opts opts);
static void tr_torrentFireMetadataCompleted(tr_torrent* tor);
@ -606,18 +615,22 @@ static bool hasAnyLocalData(tr_torrent const* tor)
return false;
}
static bool setLocalErrorIfFilesDisappeared(tr_torrent* tor)
static bool setLocalErrorIfFilesDisappeared(tr_torrent* tor, std::optional<bool> has_local_data = {})
{
bool const disappeared = tor->hasTotal() > 0 && !hasAnyLocalData(tor);
if (!has_local_data)
{
has_local_data = hasAnyLocalData(tor);
}
if (disappeared)
bool const files_disappeared = tor->hasTotal() > 0 && !*has_local_data;
if (files_disappeared)
{
tr_logAddTraceTor(tor, "[LAZY] uh oh, the files disappeared");
tor->setLocalError(_(
"No data found! Ensure your drives are connected or use \"Set Location\". To re-download, remove the torrent and re-add it."));
}
return disappeared;
return files_disappeared;
}
/**
@ -755,6 +768,14 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
tr_torrentSetIdleLimit(tor, tr_sessionGetIdleLimit(tor->session));
}
auto has_local_data = std::optional<bool>{};
if ((loaded & tr_resume::Progress) != 0)
{
// if tr_resume::load() populated checked_pieces_, initCheckedPieces()
// already looked for local data on the filesystem
has_local_data = !tor->checked_pieces_.hasNone();
}
// if we don't have a local .torrent or .magnet file already, assume the torrent is new
auto const filename = tor->hasMetadata() ? tor->torrentFile() : tor->magnetFile();
@ -795,7 +816,11 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
if (!tor->hasMetadata() && !doStart)
{
tor->prefetchMagnetMetadata = true;
tr_torrentStartNow(tor);
auto opts = torrent_start_opts{};
opts.bypass_queue = true;
opts.has_local_data = has_local_data;
torrentStart(tor, opts);
}
else if (isNewTorrentASeed(tor))
{
@ -811,11 +836,15 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
}
else if (doStart)
{
tr_torrentStart(tor);
// if checked_pieces_ got populated from the loading the resume
// file above, then torrentStart doesn't need to check again
auto opts = torrent_start_opts{};
opts.has_local_data = has_local_data;
torrentStart(tor, opts);
}
else
{
setLocalErrorIfFilesDisappeared(tor);
setLocalErrorIfFilesDisappeared(tor, has_local_data);
}
}
@ -1344,7 +1373,7 @@ static bool torrentShouldQueue(tr_torrent const* tor)
return tr_sessionCountQueueFreeSlots(tor->session, dir) == 0;
}
static void torrentStart(tr_torrent* tor, bool bypass_queue)
static void torrentStart(tr_torrent* tor, torrent_start_opts opts)
{
switch (tr_torrentGetActivity(tor))
{
@ -1354,7 +1383,7 @@ static void torrentStart(tr_torrent* tor, bool bypass_queue)
case TR_STATUS_SEED_WAIT:
case TR_STATUS_DOWNLOAD_WAIT:
if (!bypass_queue)
if (!opts.bypass_queue)
{
return; /* already queued */
}
@ -1369,7 +1398,7 @@ static void torrentStart(tr_torrent* tor, bool bypass_queue)
return;
case TR_STATUS_STOPPED:
if (!bypass_queue && torrentShouldQueue(tor))
if (!opts.bypass_queue && torrentShouldQueue(tor))
{
torrentSetQueued(tor, true);
return;
@ -1379,7 +1408,7 @@ static void torrentStart(tr_torrent* tor, bool bypass_queue)
}
/* don't allow the torrent to be started if the files disappeared */
if (setLocalErrorIfFilesDisappeared(tor))
if (setLocalErrorIfFilesDisappeared(tor, opts.has_local_data))
{
return;
}
@ -1409,7 +1438,7 @@ void tr_torrentStart(tr_torrent* tor)
{
if (tr_isTorrent(tor))
{
torrentStart(tor, false);
torrentStart(tor, {});
}
}
@ -1417,7 +1446,9 @@ void tr_torrentStartNow(tr_torrent* tor)
{
if (tr_isTorrent(tor))
{
torrentStart(tor, true);
auto opts = torrent_start_opts{};
opts.bypass_queue = true;
torrentStart(tor, opts);
}
}
@ -1435,7 +1466,10 @@ static void onVerifyDoneThreadFunc(tr_torrent* const tor)
if (tor->startAfterVerify)
{
tor->startAfterVerify = false;
torrentStart(tor, false);
auto opts = torrent_start_opts{};
opts.has_local_data = !tor->checked_pieces_.hasNone();
torrentStart(tor, opts);
}
}
@ -3137,7 +3171,7 @@ void tr_torrent::setBlocks(tr_bitfield blocks)
{
TR_ASSERT(piece < this->pieceCount());
if (checked_pieces_.test(piece))
if (isPieceChecked(piece))
{
return true;
}

View File

@ -516,7 +516,14 @@ public:
return metainfo_.infoDictOffset();
}
/// METAINFO - CHECKSUMS
/// METAINFO - PIECE CHECKSUMS
[[nodiscard]] bool isPieceChecked(tr_piece_index_t piece) const
{
return checked_pieces_.test(piece);
}
[[nodiscard]] bool checkPiece(tr_piece_index_t piece);
[[nodiscard]] bool ensurePieceIsChecked(tr_piece_index_t piece);
@ -578,8 +585,6 @@ public:
tr_torrent_metainfo metainfo_;
tr_bitfield checked_pieces_ = tr_bitfield{ 0 };
// TODO(ckerr): make private once some of torrent.cc's `tr_torrentFoo()` methods are member functions
tr_completion completion;
@ -600,8 +605,6 @@ public:
tr_interned_string error_announce_url;
std::string error_string;
bool checkPiece(tr_piece_index_t piece);
tr_sha1_digest_t obfuscated_hash = {};
/* Used when the torrent has been created with a magnet link
@ -725,8 +728,14 @@ public:
tr_file_priorities file_priorities_{ &fpm_ };
tr_files_wanted files_wanted_{ &fpm_ };
// when Transmission thinks the torrent's files were last changed
std::vector<time_t> file_mtimes_;
// true iff the piece was verified more recently than any of the piece's
// files' mtimes (file_mtimes_). If checked_pieces_.test(piece) is false,
// it means that piece needs to be checked before its data is used.
tr_bitfield checked_pieces_ = tr_bitfield{ 0 };
private:
void setFilesWanted(tr_file_index_t const* files, size_t n_files, bool wanted, bool is_bootstrapping)
{