mirror of
https://github.com/transmission/transmission
synced 2025-03-13 07:33:02 +00:00
refactor: remove tr_file.offset (#2347)
This commit is contained in:
parent
af183b1423
commit
fd96a9270b
6 changed files with 134 additions and 79 deletions
|
@ -65,7 +65,7 @@ uint64_t tr_completion::computeSizeWhenDone() const
|
|||
}
|
||||
else
|
||||
{
|
||||
size += countHasBytesInSpan(block_info_->blockSpanForPiece(piece));
|
||||
size += countHasBytesInBlocks(block_info_->blockSpanForPiece(piece));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ size_t tr_completion::countMissingBlocksInPiece(tr_piece_index_t piece) const
|
|||
|
||||
size_t tr_completion::countMissingBytesInPiece(tr_piece_index_t piece) const
|
||||
{
|
||||
return block_info_->pieceSize(piece) - countHasBytesInSpan(block_info_->blockSpanForPiece(piece));
|
||||
return block_info_->pieceSize(piece) - countHasBytesInBlocks(block_info_->blockSpanForPiece(piece));
|
||||
}
|
||||
|
||||
tr_completeness tr_completion::status() const
|
||||
|
@ -165,7 +165,7 @@ void tr_completion::setBlocks(tr_bitfield blocks)
|
|||
TR_ASSERT(std::size(blocks_) == std::size(blocks));
|
||||
|
||||
blocks_ = std::move(blocks);
|
||||
size_now_ = countHasBytesInSpan({ 0, tr_block_index_t(std::size(blocks_)) });
|
||||
size_now_ = countHasBytesInBlocks({ 0, tr_block_index_t(std::size(blocks_)) });
|
||||
size_when_done_.reset();
|
||||
has_valid_.reset();
|
||||
}
|
||||
|
@ -183,12 +183,12 @@ void tr_completion::addPiece(tr_piece_index_t piece)
|
|||
void tr_completion::removePiece(tr_piece_index_t piece)
|
||||
{
|
||||
auto const [begin, end] = block_info_->blockSpanForPiece(piece);
|
||||
size_now_ -= countHasBytesInSpan(block_info_->blockSpanForPiece(piece));
|
||||
size_now_ -= countHasBytesInBlocks(block_info_->blockSpanForPiece(piece));
|
||||
has_valid_.reset();
|
||||
blocks_.unsetSpan(begin, end);
|
||||
}
|
||||
|
||||
uint64_t tr_completion::countHasBytesInSpan(tr_block_span_t span) const
|
||||
uint64_t tr_completion::countHasBytesInBlocks(tr_block_span_t span) const
|
||||
{
|
||||
auto const [begin, end] = span;
|
||||
|
||||
|
@ -202,3 +202,55 @@ uint64_t tr_completion::countHasBytesInSpan(tr_block_span_t span) const
|
|||
|
||||
return n;
|
||||
}
|
||||
|
||||
uint64_t tr_completion::countHasBytesInSpan(tr_byte_span_t span) const
|
||||
{
|
||||
// confirm the span is valid
|
||||
span.begin = std::clamp(span.begin, uint64_t{ 0 }, block_info_->total_size);
|
||||
span.end = std::clamp(span.end, uint64_t{ 0 }, block_info_->total_size);
|
||||
auto const [begin_byte, end_byte] = span;
|
||||
if (begin_byte >= end_byte)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get the block span of the byte span
|
||||
auto const begin_block = block_info_->blockOf(begin_byte);
|
||||
auto const final_byte = end_byte - 1;
|
||||
auto const final_block = block_info_->blockOf(final_byte);
|
||||
|
||||
// if the entire span is in a single block
|
||||
if (begin_block == final_block)
|
||||
{
|
||||
return hasBlock(begin_block) ? end_byte - begin_byte : 0;
|
||||
}
|
||||
|
||||
auto total = uint64_t{};
|
||||
|
||||
// the first block
|
||||
if (hasBlock(begin_block))
|
||||
{
|
||||
uint64_t u = begin_block + 1;
|
||||
u *= block_info_->block_size;
|
||||
u -= begin_byte;
|
||||
total += u;
|
||||
}
|
||||
|
||||
// the middle blocks
|
||||
if (begin_block + 1 < final_block)
|
||||
{
|
||||
uint64_t u = blocks_.count(begin_block + 1, final_block);
|
||||
u *= block_info_->block_size;
|
||||
total += u;
|
||||
}
|
||||
|
||||
// the last block
|
||||
if (hasBlock(final_block))
|
||||
{
|
||||
uint64_t u = final_block;
|
||||
u *= block_info_->block_size;
|
||||
total += end_byte - u;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
|
|
@ -128,6 +128,8 @@ struct tr_completion
|
|||
size_when_done_.reset();
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t countHasBytesInSpan(tr_byte_span_t) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] constexpr bool hasMetainfo() const
|
||||
{
|
||||
|
@ -136,7 +138,7 @@ private:
|
|||
|
||||
[[nodiscard]] uint64_t computeHasValid() const;
|
||||
[[nodiscard]] uint64_t computeSizeWhenDone() const;
|
||||
[[nodiscard]] uint64_t countHasBytesInSpan(tr_block_span_t) const;
|
||||
[[nodiscard]] uint64_t countHasBytesInBlocks(tr_block_span_t) const;
|
||||
|
||||
torrent_view const* tor_;
|
||||
tr_block_info const* block_info_;
|
||||
|
|
|
@ -63,8 +63,15 @@ public:
|
|||
return std::size(file_pieces_);
|
||||
}
|
||||
|
||||
// TODO(ckerr) minor wart here, two identical span types
|
||||
[[nodiscard]] tr_byte_span_t byteSpan(tr_file_index_t file) const
|
||||
{
|
||||
auto const& span = file_bytes_.at(file);
|
||||
return tr_byte_span_t{ span.begin, span.end };
|
||||
}
|
||||
|
||||
private:
|
||||
using byte_span_t = index_span_t<tr_byte_index_t>;
|
||||
using byte_span_t = index_span_t<uint64_t>;
|
||||
std::vector<byte_span_t> file_bytes_;
|
||||
|
||||
std::vector<piece_span_t> file_pieces_;
|
||||
|
|
|
@ -575,15 +575,6 @@ static void torrentInitFromInfoDict(tr_torrent* tor)
|
|||
tor->obfuscated_hash = tr_sha1_digest_t{};
|
||||
}
|
||||
|
||||
// init file offsets
|
||||
auto offset = uint64_t{ 0 };
|
||||
for (tr_file_index_t i = 0, n = tor->fileCount(); i < n; ++i)
|
||||
{
|
||||
auto& file = tor->file(i);
|
||||
file.priv.offset = offset;
|
||||
offset += file.length;
|
||||
}
|
||||
|
||||
tor->fpm_.reset(tor->info);
|
||||
tor->file_priorities_.reset(&tor->fpm_);
|
||||
tor->files_wanted_.reset(&tor->fpm_);
|
||||
|
@ -1115,68 +1106,22 @@ tr_stat const* tr_torrentStat(tr_torrent* tor)
|
|||
****
|
||||
***/
|
||||
|
||||
static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t index)
|
||||
tr_file_view tr_torrentFile(tr_torrent const* tor, tr_file_index_t i)
|
||||
{
|
||||
tr_file const& f = tor->file(index);
|
||||
if (f.length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
|
||||
auto const [begin, end] = tr_torGetFileBlockSpan(tor, index);
|
||||
auto const n = end - begin;
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n == 1)
|
||||
{
|
||||
return tor->hasBlock(begin) ? f.length : 0;
|
||||
}
|
||||
|
||||
auto total = uint64_t{};
|
||||
|
||||
// the first block
|
||||
if (tor->hasBlock(begin))
|
||||
{
|
||||
total += tor->block_size - f.priv.offset % tor->block_size;
|
||||
}
|
||||
|
||||
// the middle blocks
|
||||
if (end - begin > 2)
|
||||
{
|
||||
uint64_t u = tor->completion.blocks().count(begin + 1, end - 1);
|
||||
u *= tor->block_size;
|
||||
total += u;
|
||||
}
|
||||
|
||||
// the last block
|
||||
if (tor->hasBlock(end - 1))
|
||||
{
|
||||
total += f.priv.offset + f.length - (uint64_t)tor->block_size * (end - 1);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
tr_file_view tr_torrentFile(tr_torrent const* torrent, tr_file_index_t i)
|
||||
{
|
||||
TR_ASSERT(tr_isTorrent(torrent));
|
||||
|
||||
auto const& file = torrent->file(i);
|
||||
auto const& file = tor->file(i);
|
||||
auto const* const name = file.name;
|
||||
auto const priority = torrent->file_priorities_.filePriority(i);
|
||||
auto const wanted = torrent->files_wanted_.fileWanted(i);
|
||||
auto const priority = tor->file_priorities_.filePriority(i);
|
||||
auto const wanted = tor->files_wanted_.fileWanted(i);
|
||||
auto const length = file.length;
|
||||
|
||||
if (torrent->completeness == TR_SEED || length == 0)
|
||||
if (tor->completeness == TR_SEED || length == 0)
|
||||
{
|
||||
return { name, length, length, 1.0, priority, wanted };
|
||||
}
|
||||
|
||||
auto const have = countFileBytesCompleted(torrent, i);
|
||||
auto const have = tor->completion.countHasBytesInSpan(tor->fpm_.byteSpan(i));
|
||||
return { name, have, length, have >= length ? 1.0 : have / double(length), priority, wanted };
|
||||
}
|
||||
|
||||
|
@ -2039,21 +1984,20 @@ bool tr_torrentReqIsValid(tr_torrent const* tor, tr_piece_index_t index, uint32_
|
|||
return err == 0;
|
||||
}
|
||||
|
||||
// TODO(ckerr) migrate to fpm
|
||||
// TODO(ckerr) migrate to fpm?
|
||||
tr_block_span_t tr_torGetFileBlockSpan(tr_torrent const* tor, tr_file_index_t const i)
|
||||
{
|
||||
tr_file const& file = tor->file(i);
|
||||
auto const [begin_byte, end_byte] = tor->fpm_.byteSpan(i);
|
||||
|
||||
uint64_t offset = file.priv.offset;
|
||||
tr_block_index_t const begin = offset / tor->block_size;
|
||||
if (file.length == 0)
|
||||
auto const begin_block = tor->blockOf(begin_byte);
|
||||
if (begin_byte >= end_byte)
|
||||
{
|
||||
return { begin, begin };
|
||||
return { begin_block, begin_block };
|
||||
}
|
||||
|
||||
offset += file.length - 1;
|
||||
tr_block_index_t const end = 1 + offset / tor->block_size;
|
||||
return { begin, end };
|
||||
auto const final_byte = end_byte - 1;
|
||||
auto const end_block = tor->blockOf(final_byte) + 1;
|
||||
return { begin_block, end_block };
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
@ -46,6 +46,12 @@ struct tr_block_span_t
|
|||
tr_block_index_t end;
|
||||
};
|
||||
|
||||
struct tr_byte_span_t
|
||||
{
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
};
|
||||
|
||||
struct tr_ctor;
|
||||
struct tr_error;
|
||||
struct tr_file;
|
||||
|
@ -1495,7 +1501,6 @@ void tr_torrentVerify(tr_torrent* torrent, tr_verify_done_func callback_func_or_
|
|||
|
||||
struct tr_file_priv
|
||||
{
|
||||
uint64_t offset; // file begins at the torrent's nth byte
|
||||
time_t mtime;
|
||||
bool is_renamed; // true if we're using a different path from the one in the metainfo; ie, if the user has renamed it */
|
||||
};
|
||||
|
|
|
@ -429,6 +429,51 @@ TEST_F(CompletionTest, amountDone)
|
|||
EXPECT_EQ(backup, bins);
|
||||
}
|
||||
|
||||
TEST_F(CompletionTest, countHasBytesInSpan)
|
||||
{
|
||||
// set up a fake torrent
|
||||
auto torrent = TestTorrent{};
|
||||
auto constexpr TotalSize = uint64_t{ BlockSize * 4096 } + 1;
|
||||
auto constexpr PieceSize = uint64_t{ BlockSize * 64 };
|
||||
auto const block_info = tr_block_info{ TotalSize, PieceSize };
|
||||
auto completion = tr_completion(&torrent, &block_info);
|
||||
|
||||
// torrent is complete
|
||||
auto blocks = tr_bitfield{ block_info.n_blocks };
|
||||
blocks.setHasAll();
|
||||
completion.setBlocks(blocks);
|
||||
|
||||
EXPECT_EQ(TotalSize, completion.countHasBytesInSpan({ 0, TotalSize }));
|
||||
EXPECT_EQ(TotalSize, completion.countHasBytesInSpan({ 0, TotalSize + 1 }));
|
||||
// test span that's entirely in a single block
|
||||
EXPECT_EQ(1, completion.countHasBytesInSpan({ 16, 17 }));
|
||||
EXPECT_EQ(16, completion.countHasBytesInSpan({ 16, 32 }));
|
||||
// test edge cases on block boundary
|
||||
EXPECT_EQ(1, completion.countHasBytesInSpan({ BlockSize - 1, BlockSize }));
|
||||
EXPECT_EQ(1, completion.countHasBytesInSpan({ BlockSize, BlockSize + 1 }));
|
||||
EXPECT_EQ(2, completion.countHasBytesInSpan({ BlockSize - 1, BlockSize + 1 }));
|
||||
// test edge cases on piece boundary
|
||||
EXPECT_EQ(1, completion.countHasBytesInSpan({ PieceSize - 1, PieceSize }));
|
||||
EXPECT_EQ(1, completion.countHasBytesInSpan({ PieceSize, PieceSize + 1 }));
|
||||
EXPECT_EQ(2, completion.countHasBytesInSpan({ PieceSize - 1, PieceSize + 1 }));
|
||||
|
||||
// test span that has a middle block
|
||||
EXPECT_EQ(BlockSize * 3, completion.countHasBytesInSpan({ 0, BlockSize * 3 }));
|
||||
EXPECT_EQ(BlockSize * 2, completion.countHasBytesInSpan({ BlockSize / 2, BlockSize * 2 + BlockSize / 2 }));
|
||||
|
||||
// test span where first block is missing
|
||||
blocks.unset(0);
|
||||
completion.setBlocks(blocks);
|
||||
EXPECT_EQ(BlockSize * 2, completion.countHasBytesInSpan({ 0, BlockSize * 3 }));
|
||||
EXPECT_EQ(BlockSize * 1.5, completion.countHasBytesInSpan({ BlockSize / 2, BlockSize * 2 + BlockSize / 2 }));
|
||||
// test span where final block is missing
|
||||
blocks.setHasAll();
|
||||
blocks.unset(2);
|
||||
completion.setBlocks(blocks);
|
||||
EXPECT_EQ(BlockSize * 2, completion.countHasBytesInSpan({ 0, BlockSize * 3 }));
|
||||
EXPECT_EQ(BlockSize * 1.5, completion.countHasBytesInSpan({ BlockSize / 2, BlockSize * 2 + BlockSize / 2 }));
|
||||
}
|
||||
|
||||
TEST_F(CompletionTest, status)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue