1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-02-19 04:41:11 +00:00

fix: clear verify_thread before releasing verify mutex lock (#2360)

* fix: clear verify_thread before releasing verify mutex lock

* refactor: increase the verify buffer size

* fix: uniqueness comparison for verify torrents
This commit is contained in:
Charles Kerr 2021-12-29 13:20:09 -06:00 committed by GitHub
parent 46f9582e36
commit 23b7f02100
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -7,10 +7,10 @@
*/ */
#include <algorithm> #include <algorithm>
#include <cstdlib> /* free() */
#include <ctime> #include <ctime>
#include <mutex> #include <mutex>
#include <set> #include <set>
#include <vector>
#include "transmission.h" #include "transmission.h"
#include "completion.h" #include "completion.h"
@ -31,6 +31,8 @@ static auto constexpr MsecToSleepPerSecondDuringVerify = int{ 100 };
static bool verifyTorrent(tr_torrent* tor, bool* stopFlag) static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
{ {
auto const begin = tr_time();
tr_sys_file_t fd = TR_BAD_SYS_FILE; tr_sys_file_t fd = TR_BAD_SYS_FILE;
uint64_t filePos = 0; uint64_t filePos = 0;
bool changed = false; bool changed = false;
@ -40,11 +42,8 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
tr_file_index_t fileIndex = 0; tr_file_index_t fileIndex = 0;
tr_file_index_t prevFileIndex = !fileIndex; tr_file_index_t prevFileIndex = !fileIndex;
tr_piece_index_t piece = 0; tr_piece_index_t piece = 0;
time_t const begin = tr_time(); auto buffer = std::vector<std::byte>(1024 * 256);
size_t const buflen = 1024 * 128; // 128 KiB buffer auto sha = tr_sha1_init();
auto* const buffer = static_cast<uint8_t*>(tr_malloc(buflen));
tr_sha1_ctx_t sha = tr_sha1_init();
tr_logAddTorDbg(tor, "%s", "verifying torrent..."); tr_logAddTorDbg(tor, "%s", "verifying torrent...");
tor->verify_progress = 0; tor->verify_progress = 0;
@ -73,16 +72,16 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
uint64_t leftInPiece = tor->pieceSize(piece) - piecePos; uint64_t leftInPiece = tor->pieceSize(piece) - piecePos;
uint64_t leftInFile = file_length - filePos; uint64_t leftInFile = file_length - filePos;
uint64_t bytesThisPass = std::min(leftInFile, leftInPiece); uint64_t bytesThisPass = std::min(leftInFile, leftInPiece);
bytesThisPass = std::min(bytesThisPass, uint64_t{ buflen }); bytesThisPass = std::min(bytesThisPass, uint64_t(std::size(buffer)));
/* read a bit */ /* read a bit */
if (fd != TR_BAD_SYS_FILE) if (fd != TR_BAD_SYS_FILE)
{ {
auto numRead = uint64_t{}; auto numRead = uint64_t{};
if (tr_sys_file_read_at(fd, buffer, bytesThisPass, filePos, &numRead, nullptr) && numRead > 0) if (tr_sys_file_read_at(fd, std::data(buffer), bytesThisPass, filePos, &numRead, nullptr) && numRead > 0)
{ {
bytesThisPass = numRead; bytesThisPass = numRead;
tr_sha1_update(sha, buffer, bytesThisPass); tr_sha1_update(sha, std::data(buffer), bytesThisPass);
tr_sys_file_advise(fd, filePos, bytesThisPass, TR_SYS_FILE_ADVICE_DONT_NEED, nullptr); tr_sys_file_advise(fd, filePos, bytesThisPass, TR_SYS_FILE_ADVICE_DONT_NEED, nullptr);
} }
} }
@ -143,7 +142,6 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
tor->verify_progress.reset(); tor->verify_progress.reset();
tr_sha1_final(sha); tr_sha1_final(sha);
free(buffer);
/* stopwatch */ /* stopwatch */
time_t const end = tr_time(); time_t const end = tr_time();
@ -184,6 +182,12 @@ struct verify_node
return current_size < that.current_size ? -1 : 1; return current_size < that.current_size ? -1 : 1;
} }
// tertiary compare just to ensure they don't compare equal
if (torrent->infoHash() != that.torrent->infoHash())
{
return torrent->infoHash() < that.torrent->infoHash() ? -1 : 1;
}
return 0; return 0;
} }
@ -195,8 +199,8 @@ struct verify_node
static struct verify_node currentNode; static struct verify_node currentNode;
// TODO: refactor s.t. this doesn't leak // TODO: refactor s.t. this doesn't leak
static auto& verifyList{ *new std::set<verify_node>{} }; static auto& verify_list{ *new std::set<verify_node>{} };
static tr_thread* verifyThread = nullptr; static tr_thread* verify_thread = nullptr;
static bool stopCurrent = false; static bool stopCurrent = false;
static std::mutex verify_mutex_; static std::mutex verify_mutex_;
@ -205,27 +209,26 @@ static void verifyThreadFunc(void* /*user_data*/)
{ {
for (;;) for (;;)
{ {
bool changed = false;
{ {
auto const lock = std::lock_guard(verify_mutex_); auto const lock = std::lock_guard(verify_mutex_);
stopCurrent = false; stopCurrent = false;
if (std::empty(verifyList)) if (std::empty(verify_list))
{ {
currentNode.torrent = nullptr; currentNode.torrent = nullptr;
break; verify_thread = nullptr;
return;
} }
auto const it = std::begin(verifyList); auto const it = std::begin(verify_list);
currentNode = *it; currentNode = *it;
verifyList.erase(it); verify_list.erase(it);
} }
tr_torrent* tor = currentNode.torrent; tr_torrent* tor = currentNode.torrent;
tr_logAddTorInfo(tor, "%s", _("Verifying torrent")); tr_logAddTorInfo(tor, "%s", _("Verifying torrent"));
tor->setVerifyState(TR_VERIFY_NOW); tor->setVerifyState(TR_VERIFY_NOW);
changed = verifyTorrent(tor, &stopCurrent); auto const changed = verifyTorrent(tor, &stopCurrent);
tor->setVerifyState(TR_VERIFY_NONE); tor->setVerifyState(TR_VERIFY_NONE);
TR_ASSERT(tr_isTorrent(tor)); TR_ASSERT(tr_isTorrent(tor));
@ -239,8 +242,6 @@ static void verifyThreadFunc(void* /*user_data*/)
(*currentNode.callback_func)(tor, stopCurrent, currentNode.callback_data); (*currentNode.callback_func)(tor, stopCurrent, currentNode.callback_data);
} }
} }
verifyThread = nullptr;
} }
void tr_verifyAdd(tr_torrent* tor, tr_verify_done_func callback_func, void* callback_data) void tr_verifyAdd(tr_torrent* tor, tr_verify_done_func callback_func, void* callback_data)
@ -256,11 +257,11 @@ void tr_verifyAdd(tr_torrent* tor, tr_verify_done_func callback_func, void* call
auto const lock = std::lock_guard(verify_mutex_); auto const lock = std::lock_guard(verify_mutex_);
tor->setVerifyState(TR_VERIFY_WAIT); tor->setVerifyState(TR_VERIFY_WAIT);
verifyList.insert(node); verify_list.insert(node);
if (verifyThread == nullptr) if (verify_thread == nullptr)
{ {
verifyThread = tr_threadNew(verifyThreadFunc, nullptr); verify_thread = tr_threadNew(verifyThreadFunc, nullptr);
} }
} }
@ -284,20 +285,20 @@ void tr_verifyRemove(tr_torrent* tor)
else else
{ {
auto const it = std::find_if( auto const it = std::find_if(
std::begin(verifyList), std::begin(verify_list),
std::end(verifyList), std::end(verify_list),
[tor](auto const& task) { return tor == task.torrent; }); [tor](auto const& task) { return tor == task.torrent; });
tor->setVerifyState(TR_VERIFY_NONE); tor->setVerifyState(TR_VERIFY_NONE);
if (it != std::end(verifyList)) if (it != std::end(verify_list))
{ {
if (it->callback_func != nullptr) if (it->callback_func != nullptr)
{ {
(*it->callback_func)(tor, true, it->callback_data); (*it->callback_func)(tor, true, it->callback_data);
} }
verifyList.erase(it); verify_list.erase(it);
} }
} }
@ -309,5 +310,5 @@ void tr_verifyClose(tr_session* /*session*/)
auto const lock = std::lock_guard(verify_mutex_); auto const lock = std::lock_guard(verify_mutex_);
stopCurrent = true; stopCurrent = true;
verifyList.clear(); verify_list.clear();
} }