refactor: move tr_ioFindFileLocation() to tr_file_piece_manager (#2334)
This commit is contained in:
parent
dd1379b0b6
commit
33553c5331
|
@ -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 };
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* @} */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue