refactor: move tr_ioFindFileLocation() to tr_file_piece_manager (#2334)

This commit is contained in:
Charles Kerr 2021-12-24 00:39:55 -06:00 committed by GitHub
parent dd1379b0b6
commit 33553c5331
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 127 additions and 112 deletions

View File

@ -17,26 +17,36 @@
void tr_file_piece_map::reset(tr_block_info const& block_info, uint64_t const* file_sizes, size_t n_files)
{
files_.resize(n_files);
files_.shrink_to_fit();
file_bytes_.resize(n_files);
file_bytes_.shrink_to_fit();
file_pieces_.resize(n_files);
file_pieces_.shrink_to_fit();
uint64_t offset = 0;
for (tr_file_index_t i = 0; i < n_files; ++i)
{
auto const file_size = file_sizes[i];
auto const begin_piece = block_info.pieceOf(offset);
tr_piece_index_t end_piece = 0;
auto const begin_byte = offset;
auto const begin_piece = block_info.pieceOf(begin_byte);
auto end_byte = tr_byte_index_t{};
auto end_piece = tr_piece_index_t{};
if (file_size != 0)
{
auto const last_byte = offset + file_size - 1;
auto const final_piece = block_info.pieceOf(last_byte);
end_byte = offset + file_size;
auto const final_byte = end_byte - 1;
auto const final_piece = block_info.pieceOf(final_byte);
end_piece = final_piece + 1;
}
else
{
end_byte = begin_byte;
// TODO(ckerr): should end_piece == begin_piece, same as _bytes are?
end_piece = begin_piece + 1;
}
files_[i] = piece_span_t{ begin_piece, end_piece };
file_pieces_[i] = piece_span_t{ begin_piece, end_piece };
file_bytes_[i] = byte_span_t{ begin_byte, end_byte };
offset += file_size;
}
}
@ -51,49 +61,27 @@ void tr_file_piece_map::reset(tr_info const& info)
tr_file_piece_map::piece_span_t tr_file_piece_map::pieceSpan(tr_file_index_t file) const
{
return files_[file];
return file_pieces_[file];
}
tr_file_piece_map::file_span_t tr_file_piece_map::fileSpan(tr_piece_index_t piece) const
{
struct Compare
{
int compare(tr_piece_index_t piece, piece_span_t span) const // <=>
{
if (piece < span.begin)
{
return -1;
}
if (piece >= span.end)
{
return 1;
}
return 0;
}
bool operator()(tr_piece_index_t piece, piece_span_t span) const // <
{
return compare(piece, span) < 0;
}
int compare(piece_span_t span, tr_piece_index_t piece) const // <=>
{
return -compare(piece, span);
}
bool operator()(piece_span_t span, tr_piece_index_t piece) const // <
{
return compare(span, piece) < 0;
}
};
auto const begin = std::begin(files_);
auto const& [equal_begin, equal_end] = std::equal_range(begin, std::end(files_), piece, Compare{});
auto compare = CompareToSpan<tr_piece_index_t>{};
auto const begin = std::begin(file_pieces_);
auto const& [equal_begin, equal_end] = std::equal_range(begin, std::end(file_pieces_), piece, compare);
return { tr_piece_index_t(std::distance(begin, equal_begin)), tr_piece_index_t(std::distance(begin, equal_end)) };
}
tr_file_piece_map::file_offset_t tr_file_piece_map::fileOffset(uint64_t offset) const
{
auto compare = CompareToSpan<uint64_t>{};
auto const begin = std::begin(file_bytes_);
auto const it = std::lower_bound(begin, std::end(file_bytes_), offset, compare);
tr_file_index_t const file_index = std::distance(begin, it);
auto const file_offset = offset - it->begin;
return file_offset_t{ file_index, file_offset };
}
/***
****
***/

View File

@ -33,6 +33,15 @@ public:
using file_span_t = index_span_t<tr_file_index_t>;
using piece_span_t = index_span_t<tr_piece_index_t>;
template<typename T>
struct offset_t
{
T index;
uint64_t offset;
};
using file_offset_t = offset_t<tr_file_index_t>;
explicit tr_file_piece_map(tr_info const& info)
{
reset(info);
@ -46,13 +55,55 @@ public:
[[nodiscard]] piece_span_t pieceSpan(tr_file_index_t file) const;
[[nodiscard]] file_span_t fileSpan(tr_piece_index_t piece) const;
[[nodiscard]] file_offset_t fileOffset(uint64_t offset) const;
[[nodiscard]] size_t size() const
{
return std::size(files_);
return std::size(file_pieces_);
}
private:
std::vector<piece_span_t> files_;
using byte_span_t = index_span_t<tr_byte_index_t>;
std::vector<byte_span_t> file_bytes_;
std::vector<piece_span_t> file_pieces_;
template<typename T>
struct CompareToSpan
{
using span_t = index_span_t<T>;
int compare(T item, span_t span) const // <=>
{
if (item < span.begin)
{
return -1;
}
if (item >= span.end)
{
return 1;
}
return 0;
}
bool operator()(T item, span_t span) const // <
{
return compare(item, span) < 0;
}
int compare(span_t span, T item) const // <=>
{
return -compare(item, span);
}
bool operator()(span_t span, T item) const // <
{
return compare(span, item) < 0;
}
};
};
class tr_file_priorities

View File

@ -150,52 +150,6 @@ static int readOrWriteBytes(
return err;
}
static int compareOffsetToFile(void const* a, void const* b)
{
auto const offset = *static_cast<uint64_t const*>(a);
auto const* file = static_cast<tr_file const*>(b);
if (offset < file->priv.offset)
{
return -1;
}
if (offset >= file->priv.offset + file->length)
{
return 1;
}
return 0;
}
// TODO(ckerr) migrate to fpm
void tr_ioFindFileLocation(
tr_torrent const* tor,
tr_piece_index_t pieceIndex,
uint32_t pieceOffset,
tr_file_index_t* fileIndex,
uint64_t* fileOffset)
{
TR_ASSERT(tr_isTorrent(tor));
uint64_t const offset = tr_pieceOffset(tor, pieceIndex, pieceOffset, 0);
TR_ASSERT(offset < tor->totalSize());
auto const n_files = tor->fileCount();
auto const* file = static_cast<tr_file const*>(
bsearch(&offset, tor->info.files, n_files, sizeof(tr_file), compareOffsetToFile));
TR_ASSERT(file != nullptr);
if (file != nullptr)
{
*fileIndex = file - tor->info.files;
*fileOffset = offset - file->priv.offset;
TR_ASSERT(*fileIndex < n_files);
TR_ASSERT(*fileOffset < file->length);
TR_ASSERT(tor->file(*fileIndex).priv.offset + *fileOffset == offset);
}
}
/* returns 0 on success, or an errno on failure */
static int readOrWritePiece(
tr_torrent* tor,
@ -212,9 +166,7 @@ static int readOrWritePiece(
return EINVAL;
}
auto fileIndex = tr_file_index_t{};
auto fileOffset = uint64_t{};
tr_ioFindFileLocation(tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset);
auto [fileIndex, fileOffset] = tor->fileOffset(pieceIndex, pieceOffset);
while (buflen != 0 && err == 0)
{

View File

@ -38,14 +38,4 @@ int tr_ioWrite(struct tr_torrent* tor, tr_piece_index_t pieceIndex, uint32_t off
*/
bool tr_ioTestPiece(tr_torrent* tor, tr_piece_index_t piece);
/**
* Converts a piece index + offset into a file index + offset.
*/
void tr_ioFindFileLocation(
tr_torrent const* tor,
tr_piece_index_t pieceIndex,
uint32_t pieceOffset,
tr_file_index_t* fileIndex,
uint64_t* fileOffset);
/* @} */

View File

@ -242,6 +242,16 @@ public:
return fpm_.pieceSpan(file);
}
[[nodiscard]] auto fileOffset(uint64_t offset) const
{
return fpm_.fileOffset(offset);
}
[[nodiscard]] auto fileOffset(tr_piece_index_t piece, uint32_t piece_offset) const
{
return fpm_.fileOffset(this->offset(piece, piece_offset));
}
/// WANTED
[[nodiscard]] bool pieceIsWanted(tr_piece_index_t piece) const final

View File

@ -36,6 +36,7 @@ using tr_block_index_t = uint32_t;
using tr_port = uint16_t;
using tr_tracker_tier_t = uint32_t;
using tr_tracker_id_t = uint32_t;
using tr_byte_index_t = uint64_t;
#include "announce-list.h"

View File

@ -18,7 +18,6 @@
#include "bandwidth.h"
#include "cache.h"
#include "inout.h" /* tr_ioFindFileLocation() */
#include "peer-mgr.h"
#include "torrent.h"
#include "trevent.h" /* tr_runInEventThread() */
@ -271,9 +270,7 @@ static void connection_succeeded(void* vdata)
if (tor != nullptr)
{
auto file_index = tr_file_index_t{};
auto file_offset = uint64_t{};
tr_ioFindFileLocation(tor, data->piece_index, data->piece_offset, &file_index, &file_offset);
auto const file_index = tor->fileOffset(data->piece_index, data->piece_offset).index;
w->file_urls[file_index].assign(data->real_url);
}
}
@ -527,10 +524,7 @@ static void task_request_next_chunk(struct tr_webseed_task* t)
tr_piece_index_t const step_piece = total_offset / piece_size;
uint64_t const step_piece_offset = total_offset - uint64_t(piece_size) * step_piece;
auto file_index = tr_file_index_t{};
auto file_offset = uint64_t{};
tr_ioFindFileLocation(tor, step_piece, step_piece_offset, &file_index, &file_offset);
auto const [file_index, file_offset] = tor->fileOffset(step_piece, step_piece_offset);
auto const& file = tor->file(file_index);
uint64_t this_pass = std::min(remain, file.length - file_offset);

View File

@ -47,6 +47,35 @@ protected:
}
};
TEST_F(FilePieceMapTest, fileOffset)
{
auto const fpm = tr_file_piece_map{ block_info_, std::data(FileSizes), std::size(FileSizes) };
// first byte of the first file
auto file_offset = fpm.fileOffset(0);
EXPECT_EQ(0, file_offset.index);
EXPECT_EQ(0, file_offset.offset);
// final byte of the first file
file_offset = fpm.fileOffset(FileSizes[0] - 1);
EXPECT_EQ(0, file_offset.index);
EXPECT_EQ(FileSizes[0] - 1, file_offset.offset);
// first byte of the second file
// NB: this is an edge case, second file is 0 bytes.
// The second nonzero file is file #5
file_offset = fpm.fileOffset(FileSizes[0]);
EXPECT_EQ(5, file_offset.index);
EXPECT_EQ(0, file_offset.offset);
// the last byte of in the torrent.
// NB: reverse of previous edge case, since
// the final 4 files in the torrent are all 0 bytes
file_offset = fpm.fileOffset(TotalSize - 1);
EXPECT_EQ(12, file_offset.index);
EXPECT_EQ(FileSizes[12] - 1, file_offset.offset);
}
TEST_F(FilePieceMapTest, pieceSpan)
{
// Note to reviewers: it's easy to see a nonexistent fencepost error here.