transmission/libtransmission/block-info.cc

84 lines
2.0 KiB
C++

// This file Copyright © 2007-2022 Mnemosyne LLC.
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#include <event2/util.h>
#include "transmission.h"
#include "block-info.h"
#include "tr-assert.h"
// Decide on a block size. Constraints:
// (1) most clients decline requests over 16 KiB
// (2) pieceSize must be a multiple of block size
uint32_t tr_block_info::bestBlockSize(uint64_t piece_size)
{
uint32_t b = piece_size;
auto constexpr MaxBlockSize = uint32_t{ 1024 * 16 };
while (b > MaxBlockSize)
{
b /= 2U;
}
if (b == 0 || piece_size % b != 0) // not cleanly divisible
{
return 0;
}
return b;
}
void tr_block_info::initSizes(uint64_t total_size_in, uint64_t piece_size_in)
{
total_size = total_size_in;
piece_size = piece_size_in;
block_size = bestBlockSize(piece_size);
if (piece_size == 0 || block_size == 0)
{
*this = {};
return;
}
n_pieces = (total_size + piece_size - 1) / piece_size;
auto remainder = total_size % piece_size;
final_piece_size = remainder ? remainder : piece_size;
remainder = total_size % block_size;
final_block_size = remainder ? remainder : block_size;
if (block_size != 0)
{
n_blocks = (total_size + block_size - 1) / block_size;
n_blocks_in_piece = piece_size / block_size;
n_blocks_in_final_piece = (final_piece_size + block_size - 1) / block_size;
}
#ifdef TR_ENABLE_ASSERTS
// check our work
if (block_size != 0)
{
TR_ASSERT(piece_size % block_size == 0);
}
uint64_t t = n_pieces - 1;
t *= piece_size;
t += final_piece_size;
TR_ASSERT(t == total_size);
t = n_blocks - 1;
t *= block_size;
t += final_block_size;
TR_ASSERT(t == total_size);
t = n_pieces - 1;
t *= n_blocks_in_piece;
t += n_blocks_in_final_piece;
TR_ASSERT(t == n_blocks);
#endif
}