refactor: remove tr_file.offset (#2347)

This commit is contained in:
Charles Kerr 2021-12-26 12:43:27 -06:00 committed by GitHub
parent af183b1423
commit fd96a9270b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 134 additions and 79 deletions

View File

@ -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;
}

View File

@ -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_;

View File

@ -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_;

View File

@ -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 };
}
/***

View File

@ -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 */
};

View File

@ -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)
{
}