fix file progress calculation bug (with unit test)

This commit is contained in:
Arvid Norberg 2014-11-08 18:36:54 +00:00
parent aae56c991c
commit 77363ad93e
3 changed files with 93 additions and 42 deletions

View File

@ -107,6 +107,11 @@ namespace libtorrent
class bt_peer_connection;
struct listen_socket_t;
TORRENT_EXTRA_EXPORT void initialize_file_progress(
std::vector<boost::uint64_t>& file_progress
, piece_picker const& picker, file_storage const& fs);
namespace aux
{
struct piece_checker_data;

View File

@ -10876,7 +10876,54 @@ namespace libtorrent
}
#endif
void torrent::file_progress(std::vector<size_type>& fp, int flags)
void initialize_file_progress(std::vector<boost::uint64_t>& file_progress
, piece_picker const& picker, file_storage const& fs)
{
int num_pieces = fs.num_pieces();
int num_files = fs.num_files();
file_progress.resize(num_files, 0);
// initialize the progress of each file
const int piece_size = fs.piece_length();
boost::uint64_t off = 0;
boost::uint64_t total_size = fs.total_size();
int file_index = 0;
for (int piece = 0; piece < num_pieces; ++piece, off += piece_size)
{
TORRENT_ASSERT(file_index < fs.num_files());
size_type file_offset = off - fs.file_offset(file_index);
while (file_offset >= fs.file_size(file_index))
{
++file_index;
file_offset = off - fs.file_offset(file_index);
}
TORRENT_ASSERT(file_offset <= fs.file_size(file_index));
if (!picker.have_piece(piece)) continue;
int size = (std::min)(boost::uint64_t(piece_size), total_size - off);
while (size)
{
int add = (std::min)(boost::int64_t(size), fs.file_size(file_index) - file_offset);
file_progress[file_index] += add;
TORRENT_ASSERT(file_progress[file_index]
<= fs.file_size(file_index));
size -= add;
if (size >= 0)
{
++file_index;
file_offset = 0;
}
}
}
}
void torrent::file_progress(std::vector<boost::int64_t>& fp, int flags)
{
TORRENT_ASSERT(is_single_thread());
if (!valid_metadata())
@ -10889,7 +10936,7 @@ namespace libtorrent
// if we're a seed, we don't have an m_file_progress anyway
// since we don't need one. We know we have all files
if (is_seed())
if (is_seed() || !has_picker())
{
fp.resize(m_torrent_file->num_files());
file_storage const& fs = m_torrent_file->files();
@ -10911,48 +10958,12 @@ namespace libtorrent
{
// This is the first time the client asks for file progress.
// allocate it and make sure it's up to date
m_file_progress.resize(num_files, 0);
int num_pieces = m_torrent_file->num_pieces();
// we cover the case where we're a seed above
TORRENT_ASSERT(has_picker());
// initialize the progress of each file
const int piece_size = m_torrent_file->piece_length();
boost::uint64_t off = 0;
boost::uint64_t total_size = m_torrent_file->total_size();
int file_index = 0;
file_storage const& fs = m_torrent_file->files();
for (int piece = 0; piece < num_pieces; ++piece, off += piece_size)
{
TORRENT_ASSERT(file_index < fs.num_files());
size_type file_offset = off - fs.file_offset(file_index);
if (file_offset >= fs.file_size(file_index))
{
++file_index;
continue;
}
TORRENT_ASSERT(file_offset <= fs.file_size(file_index));
if (!have_piece(piece)) continue;
int size = (std::min)(boost::uint64_t(piece_size), total_size - off);
while (size)
{
int add = (std::min)(boost::int64_t(size), fs.file_size(file_index) - file_offset);
m_file_progress[file_index] += add;
TORRENT_ASSERT(m_file_progress[file_index]
<= m_torrent_file->files().file_size(file_index));
size -= add;
if (size > 0)
{
++file_index;
file_offset = 0;
}
}
}
initialize_file_progress(m_file_progress
, picker(), m_torrent_file->files());
}
fp.resize(num_files, 0);

View File

@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/create_torrent.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/torrent.hpp"
#include <boost/tuple/tuple.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
@ -210,6 +211,40 @@ int test_main()
test_running_torrent(info, 0);
}
{
// test the initialize_file_progress function to make sure it assigns
// the correct number of bytes across the files
const int piece_size = 256;
file_storage fs;
fs.add_file("torrent/1", 0);
fs.add_file("torrent/2", 10);
fs.add_file("torrent/3", 20);
fs.add_file("torrent/4", 30);
fs.add_file("torrent/5", 40);
fs.add_file("torrent/6", 100000);
fs.add_file("torrent/7", 30);
fs.set_piece_length(piece_size);
fs.set_num_pieces((fs.total_size() + piece_size - 1) / piece_size);
for (int idx = 0; idx < fs.num_pieces(); ++idx)
{
piece_picker picker;
picker.init(4, fs.total_size() % 4, fs.num_pieces());
picker.we_have(idx);
std::vector<boost::uint64_t> fp;
initialize_file_progress(fp, picker, fs);
boost::uint64_t sum = 0;
for (int i = 0; i < fp.size(); ++i)
sum += fp[i];
TEST_EQUAL(sum, fs.piece_size(idx));
}
}
return 0;
}