fix loading resume data when in seed mode

This commit is contained in:
arvidn 2017-11-28 22:59:46 +01:00 committed by Arvid Norberg
parent 0fe2e85fee
commit f81a20a035
9 changed files with 152 additions and 89 deletions

View File

@ -1,4 +1,5 @@
* fix loading resume data when in seed mode
* fix part-file creation race condition
* fix issue with initializing settings on session construction
* fix issue with receiving interested before metadata

View File

@ -84,6 +84,8 @@ pread
preadv
pwrite
pwritev
readv
writev
ftruncate
iovec
uint8

View File

@ -209,10 +209,24 @@ namespace libtorrent
storage_interface(): m_settings(0) {}
// This function is called when the storage is to be initialized. The
// default storage will create directories and empty files at this point.
// If ``allocate_files`` is true, it will also ``ftruncate`` all files to
// their target size.
// This function is called when the *storage* on disk is to be
// initialized. The default storage will create directories and empty
// files at this point. If ``allocate_files`` is true, it will also
// ``ftruncate`` all files to their target size.
//
// This function may be called multiple time on a single instance. When a
// torrent is force-rechecked, the storage is re-initialized to trigger
// the re-check from scratch.
//
// The function is not necessarily called before other member functions.
// For instance has_any_files() and verify_resume_data() are
// called early to determine whether we may have to check all files or
// not. If we're doing a full check of the files every piece will be
// hashed, causing readv() to be called as well.
//
// Any required internals that need initialization should be done in the
// constructor. This function is called before the torrent starts to
// download.
//
// If an error occurs, ``storage_error`` should be set to reflect it.
virtual void initialize(storage_error& ec) = 0;

View File

@ -1998,15 +1998,11 @@ namespace libtorrent
if (m_seed_mode)
{
m_have_all = true;
m_ses.get_io_service().post(boost::bind(&torrent::files_checked, shared_from_this()));
m_resume_data.reset();
update_gauge();
update_state_list();
return;
}
set_state(torrent_status::checking_resume_data);
else
{
int num_pad_files = 0;
TORRENT_ASSERT(block_size() > 0);
file_storage const& fs = m_torrent_file->files();
@ -2076,6 +2072,9 @@ namespace libtorrent
if (num_pad_files > 0)
m_picker->set_num_pad_files(num_pad_files);
}
set_state(torrent_status::checking_resume_data);
std::vector<std::string> links;
#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
@ -2350,7 +2349,7 @@ namespace libtorrent
// want anything in this function to affect the state of
// m_need_save_resume_data, so we save it in a local variable and reset
// it at the end of the function.
bool need_save_resume_data = m_need_save_resume_data;
bool const need_save_resume_data = m_need_save_resume_data;
dec_refcount("check_fastresume");
TORRENT_ASSERT(is_single_thread());
@ -2497,7 +2496,14 @@ namespace libtorrent
// that when the resume data check fails. For instance, if the resume data
// is incorrect, but we don't have any files, we skip the check and initialize
// the storage to not have anything.
if (j->ret == 0)
if (m_seed_mode)
{
m_have_all = true;
files_checked();
update_gauge();
update_state_list();
}
else if (j->ret == 0)
{
// there are either no files for this torrent
// or the resume_data was accepted

View File

@ -441,10 +441,7 @@ boost::shared_ptr<torrent_info> setup_peer(tcp::socket& s, sha1_hash& ih
if (th) *th = ret;
// wait for the torrent to be ready
if ((flags & add_torrent_params::flag_seed_mode) == 0)
{
wait_for_downloading(*ses, "ses");
}
if (incoming)
{

View File

@ -165,6 +165,7 @@ void test_transfer(settings_pack const& sett)
}
TEST_CHECK(st1.state == torrent_status::seeding
|| st1.state == torrent_status::checking_resume_data
|| st1.state == torrent_status::checking_files);
TEST_CHECK(st2.state == torrent_status::downloading
|| st2.state == torrent_status::checking_resume_data);

View File

@ -173,6 +173,7 @@ void test_remap_files_gather(storage_mode_t storage_mode = storage_mode_sparse)
}
TEST_CHECK(st1.state == torrent_status::seeding
|| st1.state == torrent_status::checking_resume_data
|| st1.state == torrent_status::checking_files);
TEST_CHECK(st2.state == torrent_status::downloading
|| st2.state == torrent_status::checking_resume_data);
@ -317,6 +318,7 @@ void test_remap_files_scatter(storage_mode_t storage_mode = storage_mode_sparse)
}
TEST_CHECK(st1.state == torrent_status::seeding
|| st1.state == torrent_status::checking_resume_data
|| st1.state == torrent_status::checking_files);
TEST_CHECK(st2.state == torrent_status::downloading
|| st2.state == torrent_status::checking_resume_data);

View File

@ -118,12 +118,13 @@ void test_remove_torrent(int const remove_options
if (st2.is_finished) break;
TEST_CHECK(st1.state == torrent_status::seeding
|| st1.state == torrent_status::checking_resume_data
|| st1.state == torrent_status::checking_files);
TEST_CHECK(st2.state == torrent_status::downloading
|| st2.state == torrent_status::checking_resume_data);
// if nothing is being transferred after 2 seconds, we're failing the test
if (st1.upload_payload_rate == 0 && i > 20)
// if nothing is being transferred after 3 seconds, we're failing the test
if (st1.upload_payload_rate == 0 && i > 30)
{
TEST_ERROR("no transfer");
return;

View File

@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/peer_info.hpp"
#include <boost/make_shared.hpp>
@ -186,10 +187,15 @@ void default_tests(torrent_status const& s)
TEST_CHECK(s.time_since_upload < 1351 + 10);
TEST_CHECK(s.active_time < 1339 + 10);
TEST_EQUAL(s.finished_time, 1352);
TEST_EQUAL(s.seeding_time, 1340);
TEST_EQUAL(s.added_time, 1347);
TEST_EQUAL(s.completed_time, 1348);
TEST_CHECK(s.finished_time >= 1352);
TEST_CHECK(s.seeding_time >= 1340);
TEST_CHECK(s.added_time >= 1347);
TEST_CHECK(s.completed_time >= 1348);
TEST_CHECK(s.finished_time < 1352 + 5);
TEST_CHECK(s.seeding_time < 1340 + 5);
TEST_CHECK(s.added_time < 1347 + 5);
TEST_CHECK(s.completed_time < 1348 + 5);
}
void test_file_sizes(bool allocate)
@ -494,6 +500,39 @@ TORRENT_TEST(seed_mode_preserve)
test_seed_mode(false, false, false);
}
TORRENT_TEST(seed_mode_load_peers)
{
lt::session ses(settings());
boost::shared_ptr<torrent_info> ti = generate_torrent();
add_torrent_params p;
p.ti = ti;
p.save_path = ".";
entry rd;
rd["file-format"] = "libtorrent resume file";
rd["file-version"] = 1;
rd["info-hash"] = ti->info_hash().to_string();
rd["blocks per piece"] = std::max(1, ti->piece_length() / 0x4000);
rd["pieces"] = std::string(ti->num_pieces(), '\x01');
rd["piece_priority"] = std::string(ti->num_pieces(), '\x01');
rd["seed_mode"] = 1;
rd["peers"] = "\x01\x02\x03\x04\x30\x39";
bencode(back_inserter(p.resume_data), rd);
torrent_handle h = ses.add_torrent(p);
wait_for_alert(ses, torrent_checked_alert::alert_type, "seed_mode_load_peers");
std::vector<peer_list_entry> peers;
h.get_full_peer_list(peers);
TEST_EQUAL(peers.size(), 1);
TEST_CHECK(peers[0].ip == tcp::endpoint(address::from_string("1.2.3.4"), 12345));
}
TORRENT_TEST(resume_save_load)
{
lt::session ses(settings());