mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
fix: assertion failed "s->leftUntilDone <= s->sizeWhenDone" (#3406)
This commit is contained in:
@@ -74,6 +74,17 @@ public:
|
|||||||
return { pieceLoc(piece).block, pieceLastLoc(piece).block + 1 };
|
return { pieceLoc(piece).block, pieceLastLoc(piece).block + 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] tr_byte_span_t byteSpanForPiece(tr_piece_index_t piece) const noexcept
|
||||||
|
{
|
||||||
|
if (!isInitialized())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const offset = pieceLoc(piece).byte;
|
||||||
|
return { offset, offset + pieceSize(piece) };
|
||||||
|
}
|
||||||
|
|
||||||
struct Location
|
struct Location
|
||||||
{
|
{
|
||||||
uint64_t byte = 0;
|
uint64_t byte = 0;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ uint64_t tr_completion::computeSizeWhenDone() const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size += countHasBytesInBlocks(block_info_->blockSpanForPiece(piece));
|
size += countHasBytesInPiece(piece);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ size_t tr_completion::countMissingBlocksInPiece(tr_piece_index_t piece) const
|
|||||||
|
|
||||||
size_t tr_completion::countMissingBytesInPiece(tr_piece_index_t piece) const
|
size_t tr_completion::countMissingBytesInPiece(tr_piece_index_t piece) const
|
||||||
{
|
{
|
||||||
return block_info_->pieceSize(piece) - countHasBytesInBlocks(block_info_->blockSpanForPiece(piece));
|
return block_info_->pieceSize(piece) - countHasBytesInPiece(piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_completeness tr_completion::status() const
|
tr_completeness tr_completion::status() const
|
||||||
@@ -151,6 +151,7 @@ void tr_completion::addBlock(tr_block_index_t block)
|
|||||||
blocks_.set(block);
|
blocks_.set(block);
|
||||||
size_now_ += block_info_->blockSize(block);
|
size_now_ += block_info_->blockSize(block);
|
||||||
|
|
||||||
|
size_when_done_.reset();
|
||||||
has_valid_.reset();
|
has_valid_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ void tr_completion::setBlocks(tr_bitfield blocks)
|
|||||||
TR_ASSERT(std::size(blocks_) == std::size(blocks));
|
TR_ASSERT(std::size(blocks_) == std::size(blocks));
|
||||||
|
|
||||||
blocks_ = std::move(blocks);
|
blocks_ = std::move(blocks);
|
||||||
size_now_ = countHasBytesInBlocks({ 0, tr_block_index_t(std::size(blocks_)) });
|
size_now_ = countHasBytesInSpan({ 0, block_info_->totalSize() });
|
||||||
size_when_done_.reset();
|
size_when_done_.reset();
|
||||||
has_valid_.reset();
|
has_valid_.reset();
|
||||||
}
|
}
|
||||||
@@ -187,30 +188,12 @@ void tr_completion::addPiece(tr_piece_index_t piece)
|
|||||||
void tr_completion::removePiece(tr_piece_index_t piece)
|
void tr_completion::removePiece(tr_piece_index_t piece)
|
||||||
{
|
{
|
||||||
auto const [begin, end] = block_info_->blockSpanForPiece(piece);
|
auto const [begin, end] = block_info_->blockSpanForPiece(piece);
|
||||||
size_now_ -= countHasBytesInBlocks(block_info_->blockSpanForPiece(piece));
|
size_now_ -= countHasBytesInPiece(piece);
|
||||||
|
size_when_done_.reset();
|
||||||
has_valid_.reset();
|
has_valid_.reset();
|
||||||
blocks_.unsetSpan(begin, end);
|
blocks_.unsetSpan(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t tr_completion::countHasBytesInBlocks(tr_block_span_t span) const
|
|
||||||
{
|
|
||||||
auto const [begin, end] = span;
|
|
||||||
if (begin >= end)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t n = blocks_.count(begin, end);
|
|
||||||
n *= tr_block_info::BlockSize;
|
|
||||||
|
|
||||||
if (end == block_info_->blockCount() && blocks_.test(end - 1))
|
|
||||||
{
|
|
||||||
n -= tr_block_info::BlockSize - block_info_->blockSize(end - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t tr_completion::countHasBytesInSpan(tr_byte_span_t span) const
|
uint64_t tr_completion::countHasBytesInSpan(tr_byte_span_t span) const
|
||||||
{
|
{
|
||||||
// confirm the span is valid
|
// confirm the span is valid
|
||||||
|
|||||||
@@ -140,7 +140,11 @@ struct tr_completion
|
|||||||
private:
|
private:
|
||||||
[[nodiscard]] uint64_t computeHasValid() const;
|
[[nodiscard]] uint64_t computeHasValid() const;
|
||||||
[[nodiscard]] uint64_t computeSizeWhenDone() const;
|
[[nodiscard]] uint64_t computeSizeWhenDone() const;
|
||||||
[[nodiscard]] uint64_t countHasBytesInBlocks(tr_block_span_t) const;
|
|
||||||
|
[[nodiscard]] uint64_t countHasBytesInPiece(tr_piece_index_t piece) const
|
||||||
|
{
|
||||||
|
return countHasBytesInSpan(block_info_->byteSpanForPiece(piece));
|
||||||
|
}
|
||||||
|
|
||||||
torrent_view const* tor_;
|
torrent_view const* tor_;
|
||||||
tr_block_info const* block_info_;
|
tr_block_info const* block_info_;
|
||||||
|
|||||||
@@ -471,6 +471,36 @@ TEST_F(CompletionTest, countHasBytesInSpan)
|
|||||||
EXPECT_EQ(BlockSize * 1.5, completion.countHasBytesInSpan({ BlockSize / 2, BlockSize * 2 + BlockSize / 2 }));
|
EXPECT_EQ(BlockSize * 1.5, completion.countHasBytesInSpan({ BlockSize / 2, BlockSize * 2 + BlockSize / 2 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CompletionTest, status)
|
TEST_F(CompletionTest, wantNone)
|
||||||
{
|
{
|
||||||
|
auto torrent = TestTorrent{};
|
||||||
|
auto constexpr TotalSize = uint64_t{ BlockSize * 4096 };
|
||||||
|
auto constexpr PieceSize = uint64_t{ BlockSize * 64 };
|
||||||
|
auto const block_info = tr_block_info{ TotalSize, PieceSize };
|
||||||
|
auto completion = tr_completion(&torrent, &block_info);
|
||||||
|
|
||||||
|
// we have some data
|
||||||
|
completion.addBlock(0);
|
||||||
|
|
||||||
|
// and want nothing
|
||||||
|
for (tr_piece_index_t i = 0, n = block_info.blockCount(); i < n; ++i)
|
||||||
|
{
|
||||||
|
torrent.dnd_pieces.insert(i);
|
||||||
|
}
|
||||||
|
completion.invalidateSizeWhenDone();
|
||||||
|
|
||||||
|
EXPECT_LE(completion.hasTotal(), completion.sizeWhenDone());
|
||||||
|
EXPECT_EQ(completion.hasTotal(), block_info.BlockSize);
|
||||||
|
EXPECT_EQ(completion.sizeWhenDone(), block_info.BlockSize);
|
||||||
|
EXPECT_LE(completion.leftUntilDone(), completion.sizeWhenDone());
|
||||||
|
EXPECT_EQ(completion.leftUntilDone(), 0);
|
||||||
|
|
||||||
|
// but we magically get a block anyway
|
||||||
|
completion.addBlock(1);
|
||||||
|
|
||||||
|
EXPECT_LE(completion.hasTotal(), completion.sizeWhenDone());
|
||||||
|
EXPECT_EQ(completion.hasTotal(), 2 * block_info.BlockSize);
|
||||||
|
EXPECT_EQ(completion.sizeWhenDone(), 2 * block_info.BlockSize);
|
||||||
|
EXPECT_LE(completion.leftUntilDone(), completion.sizeWhenDone());
|
||||||
|
EXPECT_EQ(completion.leftUntilDone(), 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user