From 385a119fb1bfbebc53a8c768d4089e0311906123 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 7 Jan 2022 13:13:37 -0600 Subject: [PATCH] refactor: make tr_torrent aggregates tr_block_info instead of subclassing (#2376) --- libtransmission/block-info.h | 53 ++++++++--- libtransmission/inout.cc | 4 +- libtransmission/peer-mgr.cc | 5 +- libtransmission/peer-msgs.cc | 5 +- libtransmission/resume.cc | 2 +- libtransmission/torrent-metainfo.h | 70 ++++++++++++--- libtransmission/torrent.cc | 8 +- libtransmission/torrent.h | 127 +++++++++++++++++---------- libtransmission/webseed.cc | 14 +-- tests/libtransmission/move-test.cc | 8 +- tests/libtransmission/rename-test.cc | 14 +-- 11 files changed, 204 insertions(+), 106 deletions(-) diff --git a/libtransmission/block-info.h b/libtransmission/block-info.h index ab05e4f6c..5a3e2b288 100644 --- a/libtransmission/block-info.h +++ b/libtransmission/block-info.h @@ -31,7 +31,28 @@ struct tr_block_info void initSizes(uint64_t total_size_in, uint64_t piece_size_in); - constexpr tr_piece_index_t pieceForBlock(tr_block_index_t block) const + [[nodiscard]] constexpr auto blockCount() const + { + return n_blocks; + } + + [[nodiscard]] constexpr auto blockSize() const + { + return block_size; + } + + [[nodiscard]] constexpr auto blockSize(tr_block_index_t block) const + { + // how many bytes are in this block? + return block + 1 == n_blocks ? final_block_size : blockSize(); + } + + [[nodiscard]] constexpr auto pieceCount() const + { + return n_pieces; + } + + [[nodiscard]] constexpr tr_piece_index_t pieceForBlock(tr_block_index_t block) const { // if not initialized yet, don't divide by zero if (n_blocks_in_piece == 0) @@ -42,19 +63,18 @@ struct tr_block_info return block / n_blocks_in_piece; } - constexpr uint32_t pieceSize(tr_piece_index_t piece) const + [[nodiscard]] constexpr auto pieceSize() const + { + return piece_size; + } + + [[nodiscard]] constexpr auto pieceSize(tr_piece_index_t piece) const { // how many bytes are in this piece? - return piece + 1 == n_pieces ? final_piece_size : piece_size; + return piece + 1 == n_pieces ? final_piece_size : pieceSize(); } - constexpr uint32_t blockSize(tr_block_index_t block) const - { - // how many bytes are in this block? - return block + 1 == n_blocks ? final_block_size : block_size; - } - - constexpr tr_piece_index_t pieceOf(uint64_t offset) const + [[nodiscard]] constexpr tr_piece_index_t pieceOf(uint64_t offset) const { // if not initialized yet, don't divide by zero if (piece_size == 0) @@ -71,7 +91,7 @@ struct tr_block_info return offset / piece_size; } - constexpr tr_block_index_t blockOf(uint64_t offset) const + [[nodiscard]] constexpr tr_block_index_t blockOf(uint64_t offset) const { // if not initialized yet, don't divide by zero if (block_size == 0) @@ -88,7 +108,7 @@ struct tr_block_info return offset / block_size; } - constexpr uint64_t offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + [[nodiscard]] constexpr uint64_t offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const { auto ret = piece_size; ret *= piece; @@ -97,12 +117,12 @@ struct tr_block_info return ret; } - constexpr tr_block_index_t blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + [[nodiscard]] constexpr auto blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const { return blockOf(this->offset(piece, offset, length)); } - constexpr tr_block_span_t blockSpanForPiece(tr_piece_index_t piece) const + [[nodiscard]] constexpr tr_block_span_t blockSpanForPiece(tr_piece_index_t piece) const { if (block_size == 0) { @@ -114,5 +134,10 @@ struct tr_block_info return { begin, end }; } + [[nodiscard]] constexpr auto totalSize() const + { + return total_size; + } + static uint32_t bestBlockSize(uint64_t piece_size); }; diff --git a/libtransmission/inout.cc b/libtransmission/inout.cc index 6bcf91546..85aa3c77d 100644 --- a/libtransmission/inout.cc +++ b/libtransmission/inout.cc @@ -211,12 +211,12 @@ static std::optional recalculateHash(tr_torrent* tor, tr_piece TR_ASSERT(tor != nullptr); TR_ASSERT(piece < tor->pieceCount()); - auto bytes_left = size_t{ tor->pieceSize(piece) }; + auto bytes_left = size_t(tor->pieceSize(piece)); auto offset = uint32_t{}; tr_ioPrefetch(tor, piece, offset, bytes_left); auto sha = tr_sha1_init(); - auto buffer = std::vector(tor->block_size); + auto buffer = std::vector(tor->blockSize()); while (bytes_left != 0) { size_t const len = std::min(bytes_left, std::size(buffer)); diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index d66a20b8b..8a3b68856 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -12,7 +12,6 @@ #include /* qsort */ #include /* memcpy, memcmp, strstr */ #include -#include #include #include @@ -225,7 +224,7 @@ tr_peer::tr_peer(tr_torrent const* tor, peer_atom* atom_in) : session{ tor->session } , atom{ atom_in } , swarm{ tor->swarm } - , blame{ tor->n_blocks } + , blame{ tor->blockCount() } , have{ tor->pieceCount() } { } @@ -548,7 +547,7 @@ static void updateEndgame(tr_swarm* s) { /* we consider ourselves to be in endgame if the number of bytes we've got requested is >= the number of bytes left to download */ - s->endgame = uint64_t(std::size(s->active_requests)) * s->tor->block_size >= s->tor->leftUntilDone(); + s->endgame = uint64_t(std::size(s->active_requests)) * s->tor->blockSize() >= s->tor->leftUntilDone(); } std::vector tr_peerMgrGetNextRequests(tr_torrent* torrent, tr_peer const* peer, size_t numwant) diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index 498d3a5cd..f6f314bd9 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -12,7 +12,6 @@ #include #include #include -#include #include // std::unique_ptr #include @@ -2032,7 +2031,7 @@ static void updateDesiredRequestCount(tr_peerMsgsImpl* msgs) * many requests we should send to this peer */ size_t constexpr Floor = 32; size_t constexpr Seconds = RequestBufSecs; - size_t const estimated_blocks_in_period = (rate_Bps * Seconds) / torrent->block_size; + size_t const estimated_blocks_in_period = (rate_Bps * Seconds) / torrent->blockSize(); size_t const ceil = msgs->reqq ? *msgs->reqq : 250; msgs->desired_request_count = std::clamp(estimated_blocks_in_period, Floor, ceil); } @@ -2197,7 +2196,7 @@ static size_t fillOutputBuffer(tr_peerMsgsImpl* msgs, time_t now) *** Data Blocks **/ - if (tr_peerIoGetWriteBufferSpace(msgs->io, now) >= msgs->torrent->block_size && popNextRequest(msgs, &req)) + if (tr_peerIoGetWriteBufferSpace(msgs->io, now) >= msgs->torrent->blockSize() && popNextRequest(msgs, &req)) { --msgs->prefetchCount; diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc index b9cf7d03c..62bad57f2 100644 --- a/libtransmission/resume.cc +++ b/libtransmission/resume.cc @@ -591,7 +591,7 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor) /// COMPLETION - auto blocks = tr_bitfield{ tor->n_blocks }; + auto blocks = tr_bitfield{ tor->blockCount() }; char const* err = nullptr; auto sv = std::string_view{}; tr_variant const* const b = tr_variantDictFind(prog, TR_KEY_blocks); diff --git a/libtransmission/torrent-metainfo.h b/libtransmission/torrent-metainfo.h index a0185e812..d6d12e76a 100644 --- a/libtransmission/torrent-metainfo.h +++ b/libtransmission/torrent-metainfo.h @@ -24,6 +24,11 @@ struct tr_info; struct tr_torrent_metainfo : public tr_magnet_metainfo { + [[nodiscard]] constexpr auto const& blockInfo() const + { + return block_info_; + } + public: tr_torrent_metainfo() = default; ~tr_torrent_metainfo() override = default; @@ -41,31 +46,73 @@ public: // load multiple files. bool parseTorrentFile(std::string_view benc_filename, std::vector* buffer = nullptr, tr_error** error = nullptr); - auto const& blockInfo() const + /// BLOCK INFO + + [[nodiscard]] constexpr auto blockCount() const { - return block_info_; + return blockInfo().blockCount(); } - auto pieceCount() const + [[nodiscard]] constexpr auto blockOf(uint64_t offset) const { - return block_info_.n_pieces; + return blockInfo().blockOf(offset); } - auto pieceSize() const + [[nodiscard]] constexpr auto blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const { - return block_info_.piece_size; + return blockInfo().blockOf(piece, offset, length); } - auto totalSize() const + [[nodiscard]] constexpr auto blockSize() const { - return block_info_.total_size; + return blockInfo().blockSize(); } + [[nodiscard]] constexpr auto blockSize(tr_block_index_t block) const + { + return blockInfo().blockSize(block); + } + [[nodiscard]] constexpr auto blockSpanForPiece(tr_piece_index_t piece) const + { + return blockInfo().blockSpanForPiece(piece); + } + [[nodiscard]] constexpr auto offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + return blockInfo().offset(piece, offset, length); + } + [[nodiscard]] constexpr auto pieceCount() const + { + return blockInfo().pieceCount(); + } + [[nodiscard]] constexpr auto pieceForBlock(tr_block_index_t block) const + { + return blockInfo().pieceForBlock(block); + } + [[nodiscard]] constexpr auto pieceOf(uint64_t offset) const + { + return blockInfo().pieceOf(offset); + } + [[nodiscard]] constexpr auto pieceSize() const + { + return blockInfo().pieceSize(); + } + [[nodiscard]] constexpr auto pieceSize(tr_piece_index_t piece) const + { + return blockInfo().pieceSize(piece); + } + [[nodiscard]] constexpr auto totalSize() const + { + return blockInfo().totalSize(); + } + auto const& comment() const { return comment_; } - auto const& creator() const { return creator_; } + [[nodiscard]] auto const& source() const + { + return source_; + } auto const& files() const { @@ -84,11 +131,6 @@ public: [[nodiscard]] tr_sha1_digest_t const& pieceHash(tr_piece_index_t piece) const; - [[nodiscard]] auto const& source() const - { - return source_; - } - [[nodiscard]] auto const& dateCreated() const { return date_created_; diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 747b6be60..0f79a6718 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -561,8 +561,8 @@ static void tr_torrentFireMetadataCompleted(tr_torrent* tor); static void torrentInitFromInfoDict(tr_torrent* tor) { - tor->initSizes(tor->totalSize(), tor->pieceSize()); - tor->completion = tr_completion{ tor, tor }; + tor->block_info.initSizes(tor->info.totalSize, tor->info.pieceSize); + tor->completion = tr_completion{ tor, &tor->block_info }; auto const obfuscated = tr_sha1("req2"sv, tor->infoHash()); if (obfuscated) { @@ -579,7 +579,7 @@ static void torrentInitFromInfoDict(tr_torrent* tor) tor->file_mtimes_.resize(tor->fileCount()); tor->file_priorities_.reset(&tor->fpm_); tor->files_wanted_.reset(&tor->fpm_); - tor->checked_pieces_ = tr_bitfield{ tor->pieceCount() }; + tor->checked_pieces_ = tr_bitfield{ size_t(tor->pieceCount()) }; } void tr_torrentGotNewInfoDict(tr_torrent* tor) @@ -1933,7 +1933,7 @@ void tr_torrentGetBlockLocation( uint32_t* length) { uint64_t pos = block; - pos *= tor->block_size; + pos *= tor->blockSize(); *piece = pos / tor->pieceSize(); uint64_t piece_begin = tor->pieceSize(); piece_begin *= *piece; diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 7f5543cab..57ea45db3 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -105,18 +105,16 @@ tr_torrent_activity tr_torrentGetActivity(tr_torrent const* tor); struct tr_incomplete_metadata; /** @brief Torrent object */ -struct tr_torrent - : public tr_block_info - , public tr_completion::torrent_view +struct tr_torrent : public tr_completion::torrent_view { public: - tr_torrent(tr_info const& inf) - : tr_block_info{ inf.totalSize, inf.pieceSize } - , completion{ this, this } + explicit tr_torrent(tr_info const& inf) + : block_info{ inf.totalSize, inf.pieceSize } + , completion{ this, &this->block_info } { } - virtual ~tr_torrent() override = default; + ~tr_torrent() override = default; void setLocation( std::string_view location, @@ -154,6 +152,66 @@ public: unsigned int speedLimitBps(tr_direction) const; + /// BLOCK INFO + + [[nodiscard]] constexpr auto const& blockInfo() const + { + return block_info; + } + + [[nodiscard]] constexpr auto blockCount() const + { + return blockInfo().blockCount(); + } + [[nodiscard]] constexpr auto blockOf(uint64_t offset) const + { + return blockInfo().blockOf(offset); + } + [[nodiscard]] constexpr auto blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + return blockInfo().blockOf(piece, offset, length); + } + [[nodiscard]] constexpr auto blockSize() const + { + return blockInfo().blockSize(); + } + [[nodiscard]] constexpr auto blockSize(tr_block_index_t block) const + { + return blockInfo().blockSize(block); + } + [[nodiscard]] constexpr auto blockSpanForPiece(tr_piece_index_t piece) const + { + return blockInfo().blockSpanForPiece(piece); + } + [[nodiscard]] constexpr auto offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + return blockInfo().offset(piece, offset, length); + } + [[nodiscard]] constexpr auto pieceCount() const + { + return blockInfo().pieceCount(); + } + [[nodiscard]] constexpr auto pieceForBlock(tr_block_index_t block) const + { + return blockInfo().pieceForBlock(block); + } + [[nodiscard]] constexpr auto pieceOf(uint64_t offset) const + { + return blockInfo().pieceOf(offset); + } + [[nodiscard]] constexpr auto pieceSize() const + { + return blockInfo().pieceSize(); + } + [[nodiscard]] constexpr auto pieceSize(tr_piece_index_t piece) const + { + return blockInfo().pieceSize(piece); + } + [[nodiscard]] constexpr auto totalSize() const + { + return blockInfo().totalSize(); + } + /// COMPLETION [[nodiscard]] uint64_t leftUntilDone() const @@ -352,19 +410,29 @@ public: /// METAINFO - TRACKERS + [[nodiscard]] auto const& announceList() const + { + return *this->info.announce_list; + } + + [[nodiscard]] auto& announceList() + { + return *this->info.announce_list; + } + [[nodiscard]] auto trackerCount() const { - return std::size(*info.announce_list); + return std::size(this->announceList()); } [[nodiscard]] auto const& tracker(size_t i) const { - return info.announce_list->at(i); + return this->announceList().at(i); } [[nodiscard]] auto tiers() const { - return info.announce_list->tiers(); + return this->announceList().tiers(); } /// METAINFO - WEBSEEDS @@ -381,13 +449,6 @@ public: return info.webseeds[i]; } - [[nodiscard]] auto& webseed(size_t i) - { - TR_ASSERT(i < webseedCount()); - - return info.webseeds[i]; - } - /// METAINFO - OTHER void setName(std::string_view name); @@ -407,41 +468,11 @@ public: return !this->isPrivate(); } - [[nodiscard]] auto pieceCount() const - { - return this->info.pieceCount; - } - - [[nodiscard]] auto pieceSize() const - { - return this->info.pieceSize; - } - - [[nodiscard]] auto pieceSize(tr_piece_index_t i) const - { - return tr_block_info::pieceSize(i); - } - - [[nodiscard]] auto totalSize() const - { - return this->info.totalSize; - } - [[nodiscard]] auto infoHashString() const { return this->info.hashString; } - [[nodiscard]] auto const& announceList() const - { - return *this->info.announce_list; - } - - [[nodiscard]] auto& announceList() - { - return *this->info.announce_list; - } - [[nodiscard]] auto const& torrentFile() const { return this->info.torrent; @@ -559,6 +590,8 @@ public: tr_bitfield checked_pieces_ = tr_bitfield{ 0 }; + tr_block_info block_info; + // TODO(ckerr): make private once some of torrent.cc's `tr_torrentFoo()` methods are member functions tr_completion completion; diff --git a/libtransmission/webseed.cc b/libtransmission/webseed.cc index f7a5019a3..9442c6adc 100644 --- a/libtransmission/webseed.cc +++ b/libtransmission/webseed.cc @@ -218,7 +218,7 @@ static void write_block_func(void* vdata) auto* const tor = tr_torrentFindFromId(data->session, data->torrent_id); if (tor != nullptr) { - uint32_t const block_size = tor->block_size; + uint32_t const block_size = tor->blockSize(); uint32_t len = evbuffer_get_length(buf); uint32_t const offset_end = data->block_offset + len; tr_cache* cache = data->session->cache; @@ -382,11 +382,11 @@ static void on_idle(tr_webseed* w) task->webseed = w; task->block = begin; task->piece_index = tor->pieceForBlock(begin); - task->piece_offset = tor->block_size * begin - tor->pieceSize() * task->piece_index; - task->length = (end - 1 - begin) * tor->block_size + tor->blockSize(end - 1); + task->piece_offset = tor->blockSize() * begin - tor->pieceSize() * task->piece_index; + task->length = (end - 1 - begin) * tor->blockSize() + tor->blockSize(end - 1); task->blocks_done = 0; task->response_code = 0; - task->block_size = tor->block_size; + task->block_size = tor->blockSize(); task->content = evbuffer_new(); evbuffer_add_cb(task->content, on_content_changed, task); w->tasks.insert(task); @@ -435,7 +435,7 @@ static void web_response_func( if (!success) { - tr_block_index_t const blocks_remain = (t->length + tor->block_size - 1) / tor->block_size - t->blocks_done; + tr_block_index_t const blocks_remain = (t->length + tor->blockSize() - 1) / tor->blockSize() - t->blocks_done; if (blocks_remain != 0) { @@ -458,7 +458,7 @@ static void web_response_func( } else { - uint32_t const bytes_done = t->blocks_done * tor->block_size; + uint32_t const bytes_done = t->blocks_done * tor->blockSize(); uint32_t const buf_len = evbuffer_get_length(t->content); if (bytes_done + buf_len < t->length) @@ -518,7 +518,7 @@ static void task_request_next_chunk(struct tr_webseed_task* t) auto& urls = t->webseed->file_urls; auto const piece_size = tor->pieceSize(); - uint64_t const remain = t->length - t->blocks_done * tor->block_size - evbuffer_get_length(t->content); + uint64_t const remain = t->length - t->blocks_done * tor->blockSize() - evbuffer_get_length(t->content); auto const total_offset = tor->offset(t->piece_index, t->piece_offset, t->length - remain); tr_piece_index_t const step_piece = total_offset / piece_size; diff --git a/tests/libtransmission/move-test.cc b/tests/libtransmission/move-test.cc index 8a511d622..33c8276d2 100644 --- a/tests/libtransmission/move-test.cc +++ b/tests/libtransmission/move-test.cc @@ -80,14 +80,14 @@ TEST_P(IncompleteDirTest, incompleteDir) auto const test_incomplete_dir_threadfunc = [](void* vdata) noexcept { auto* data = static_cast(vdata); - tr_cacheWriteBlock(data->session->cache, data->tor, 0, data->offset, data->tor->block_size, data->buf); + tr_cacheWriteBlock(data->session->cache, data->tor, 0, data->offset, data->tor->blockSize(), data->buf); tr_torrentGotBlock(data->tor, data->block); data->done = true; }; // now finish writing it { - char* zero_block = tr_new0(char, tor->block_size); + char* zero_block = tr_new0(char, tor->blockSize()); struct TestIncompleteDirData data = {}; data.session = session_; @@ -98,10 +98,10 @@ TEST_P(IncompleteDirTest, incompleteDir) for (tr_block_index_t block_index = begin; block_index < end; ++block_index) { - evbuffer_add(data.buf, zero_block, tor->block_size); + evbuffer_add(data.buf, zero_block, tor->blockSize()); data.block = block_index; data.done = false; - data.offset = data.block * tor->block_size; + data.offset = data.block * tor->blockSize(); tr_runInEventThread(session_, test_incomplete_dir_threadfunc, &data); auto const test = [&data]() diff --git a/tests/libtransmission/rename-test.cc b/tests/libtransmission/rename-test.cc index d95aace44..ad9c2082d 100644 --- a/tests/libtransmission/rename-test.cc +++ b/tests/libtransmission/rename-test.cc @@ -66,15 +66,15 @@ protected: sync(); } - tr_torrent* createTorrentFromBase64Metainfo(tr_ctor* ctor, char const* metainfo_base64) + tr_torrent* createTorrentFromBase64Metainfo(tr_ctor* ctor, char const* benc_base64) { // create the torrent ctor - size_t metainfo_len; - auto* metainfo = static_cast(tr_base64_decode_str(metainfo_base64, &metainfo_len)); - EXPECT_NE(nullptr, metainfo); - EXPECT_LT(size_t(0), metainfo_len); + size_t benc_len; + auto* benc = static_cast(tr_base64_decode_str(benc_base64, &benc_len)); + EXPECT_NE(nullptr, benc); + EXPECT_LT(size_t(0), benc_len); tr_error* error = nullptr; - EXPECT_TRUE(tr_ctorSetMetainfo(ctor, metainfo, metainfo_len, &error)); + EXPECT_TRUE(tr_ctorSetMetainfo(ctor, benc, benc_len, &error)); EXPECT_EQ(nullptr, error); tr_ctorSetPaused(ctor, TR_FORCE, true); @@ -83,7 +83,7 @@ protected: EXPECT_NE(nullptr, tor); // cleanup - tr_free(metainfo); + tr_free(benc); return tor; }