fix bug where disk cache was wiped out after completion file-checking. factor out sim test utilities and reuse them in the regression test

This commit is contained in:
arvidn 2016-03-06 21:42:18 -05:00
parent 3fa3004b85
commit f5d5ac4f3a
9 changed files with 347 additions and 123 deletions

View File

@ -459,7 +459,13 @@ namespace libtorrent
void flush_cache(); void flush_cache();
void pause(bool graceful = false); void pause(bool graceful = false);
void resume(); void resume();
void set_allow_peers(bool b, bool graceful_pause = false);
enum pause_flags_t
{
flag_graceful_pause = 1,
flag_clear_disk_cache = 2
};
void set_allow_peers(bool b, int flags = flag_clear_disk_cache);
void set_announce_to_dht(bool b) { m_announce_to_dht = b; } void set_announce_to_dht(bool b) { m_announce_to_dht = b; }
void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; } void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; }
void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; } void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; }
@ -468,7 +474,7 @@ namespace libtorrent
int started() const { return m_started; } int started() const { return m_started; }
void step_session_time(int seconds); void step_session_time(int seconds);
void do_pause(); void do_pause(bool clear_disk_cache = true);
void do_resume(); void do_resume();
int finished_time() const; int finished_time() const;

View File

@ -15,6 +15,7 @@ project
<source>setup_swarm.cpp <source>setup_swarm.cpp
<source>setup_dht.cpp <source>setup_dht.cpp
<source>create_torrent.cpp <source>create_torrent.cpp
<source>utils.cpp
: default-build : default-build
<threading>multi <threading>multi
<invariant-checks>full <invariant-checks>full
@ -23,6 +24,7 @@ project
; ;
alias libtorrent-sims : alias libtorrent-sims :
[ run test_checking.cpp ]
[ run test_optimistic_unchoke.cpp ] [ run test_optimistic_unchoke.cpp ]
[ run test_transfer.cpp ] [ run test_transfer.cpp ]
[ run test_http_connection.cpp ] [ run test_http_connection.cpp ]

View File

@ -0,0 +1,115 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/session.hpp"
#include "libtorrent/deadline_timer.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/torrent_status.hpp"
#include "simulator/simulator.hpp"
#include "test.hpp"
#include "settings.hpp"
#include "create_torrent.hpp"
#include "utils.hpp"
template <typename Setup, typename Test>
void run_test(Setup const& setup, Test const& test)
{
// this is a seeding torrent
lt::add_torrent_params atp = create_torrent(0, true);
sim::default_config network_cfg;
sim::simulation sim{network_cfg};
auto ios = std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
sim, lt::address_v4::from_string("50.0.0.1")));
lt::session_proxy zombie;
// setup settings pack to use for the session (customization point)
lt::settings_pack pack = settings();
setup(atp, pack);
auto ses = std::make_shared<lt::session>(pack, *ios);
ses->async_add_torrent(atp);
print_alerts(*ses);
lt::deadline_timer timer(*ios);
timer.expires_from_now(lt::seconds(6));
timer.async_wait([&](lt::error_code const& ec)
{
test(*ses);
// shut down
ses->set_alert_notify([]{});
zombie = ses->abort();
ses.reset();
});
sim.run();
}
TORRENT_TEST(cache_after_checking)
{
run_test(
[](lt::add_torrent_params& atp, lt::settings_pack& p) {
atp.flags |= lt::add_torrent_params::flag_auto_managed;
p.set_int(lt::settings_pack::cache_size, 100);
},
[](lt::session& ses) {
int cache = get_cache_size(ses);
TEST_CHECK(cache > 0);
std::vector<lt::torrent_handle> tor = ses.get_torrents();
TEST_EQUAL(tor.size(), 1);
TEST_EQUAL(tor[0].status().is_seeding, true);
});
}
TORRENT_TEST(checking_no_cache)
{
run_test(
[](lt::add_torrent_params& atp, lt::settings_pack& p) {
atp.flags |= lt::add_torrent_params::flag_auto_managed;
p.set_int(lt::settings_pack::cache_size, 0);
},
[](lt::session& ses) {
int cache = get_cache_size(ses);
TEST_EQUAL(cache, 0);
std::vector<lt::torrent_handle> tor = ses.get_torrents();
TEST_EQUAL(tor.size(), 1);
TEST_EQUAL(tor[0].status().is_seeding, true);
});
}

View File

@ -45,16 +45,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "simulator/simulator.hpp" #include "simulator/simulator.hpp"
#include "simulator/socks_server.hpp" #include "simulator/socks_server.hpp"
#include "setup_swarm.hpp" #include "setup_swarm.hpp"
#include "utils.hpp"
using namespace sim; using namespace sim;
namespace lt = libtorrent; namespace lt = libtorrent;
enum flags_t
{
ipv6 = 1,
};
template <typename Setup, typename HandleAlerts, typename Test> template <typename Setup, typename HandleAlerts, typename Test>
void run_test( void run_test(
Setup const& setup Setup const& setup
@ -64,8 +60,6 @@ void run_test(
{ {
using namespace libtorrent; using namespace libtorrent;
lt::time_point start_time = lt::clock_type::now();
const bool use_ipv6 = flags & ipv6; const bool use_ipv6 = flags & ipv6;
char const* peer0_ip[2] = { "50.0.0.1", "feed:face:baad:f00d::1" }; char const* peer0_ip[2] = { "50.0.0.1", "feed:face:baad:f00d::1" };
@ -113,32 +107,15 @@ void run_test(
setup(*ses[0], *ses[1]); setup(*ses[0], *ses[1]);
// only monitor alerts for session 0 (the downloader) // only monitor alerts for session 0 (the downloader)
ses[0]->set_alert_notify([&] { ios0.post([&] { print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
std::vector<lt::alert*> alerts;
ses[0]->pop_alerts(&alerts);
for (lt::alert const* a : alerts)
{
printf("%-3d [0] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
if (auto ta = alert_cast<lt::torrent_added_alert>(a)) if (auto ta = alert_cast<lt::torrent_added_alert>(a))
{ {
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
} }
// call the user handler on_alert(ses, a);
on_alert(*ses[0], a); });
}
} ); } );
ses[1]->set_alert_notify([&] { ios0.post([&] { print_alerts(*ses[1]);
std::vector<lt::alert*> alerts;
ses[1]->pop_alerts(&alerts);
for (lt::alert const* a : alerts)
{
printf("%-3d [1] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
}
} ); } );
// the first peer is a downloader, the second peer is a seed // the first peer is a downloader, the second peer is a seed
lt::add_torrent_params params = create_torrent(1); lt::add_torrent_params params = create_torrent(1);
@ -170,85 +147,6 @@ void run_test(
sim.run(); sim.run();
} }
void utp_only(lt::session& ses)
{
using namespace libtorrent;
settings_pack p;
utp_only(p);
ses.apply_settings(p);
}
void enable_enc(lt::session& ses)
{
using namespace libtorrent;
settings_pack p;
enable_enc(p);
ses.apply_settings(p);
}
void filter_ips(lt::session& ses)
{
using namespace libtorrent;
ip_filter filter;
filter.add_rule(asio::ip::address_v4::from_string("50.0.0.1")
, asio::ip::address_v4::from_string("50.0.0.2"), ip_filter::blocked);
ses.set_ip_filter(filter);
}
void set_cache_size(lt::session& ses, int val)
{
using namespace libtorrent;
settings_pack pack;
pack.set_int(settings_pack::cache_size, val);
ses.apply_settings(pack);
}
int get_cache_size(lt::session& ses)
{
using namespace libtorrent;
std::vector<stats_metric> stats = session_stats_metrics();
int const read_cache_idx = find_metric_idx("disk.read_cache_blocks");
int const write_cache_idx = find_metric_idx("disk.write_cache_blocks");
TEST_CHECK(read_cache_idx >= 0);
TEST_CHECK(write_cache_idx >= 0);
ses.set_alert_notify([](){});
ses.post_session_stats();
std::vector<alert*> alerts;
ses.pop_alerts(&alerts);
int cache_size = -1;
for (auto const a : alerts)
{
if (auto const* st = alert_cast<session_stats_alert>(a))
{
cache_size = st->values[read_cache_idx];
cache_size += st->values[write_cache_idx];
break;
}
}
return cache_size;
}
void set_proxy(lt::session& ses, int proxy_type, int flags = 0, bool proxy_peer_connections = true)
{
// apply the proxy settings to session 0
using namespace libtorrent;
settings_pack p;
p.set_int(settings_pack::proxy_type, proxy_type);
if (proxy_type == settings_pack::socks4)
p.set_int(settings_pack::proxy_port, 4444);
else
p.set_int(settings_pack::proxy_port, 5555);
if (flags & ipv6)
p.set_str(settings_pack::proxy_hostname, "2001::2");
else
p.set_str(settings_pack::proxy_hostname, "50.50.50.50");
p.set_bool(settings_pack::proxy_hostnames, true);
p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections);
p.set_bool(settings_pack::proxy_tracker_connections, true);
ses.apply_settings(p);
}
TORRENT_TEST(socks4_tcp) TORRENT_TEST(socks4_tcp)
{ {
using namespace libtorrent; using namespace libtorrent;

139
simulation/utils.cpp Normal file
View File

@ -0,0 +1,139 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "utils.hpp"
#include "test.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/settings_pack.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/session_stats.hpp"
#include "libtorrent/alert.hpp"
#include "setup_swarm.hpp"
using namespace libtorrent;
void utp_only(lt::session& ses)
{
settings_pack p;
utp_only(p);
ses.apply_settings(p);
}
void enable_enc(lt::session& ses)
{
settings_pack p;
enable_enc(p);
ses.apply_settings(p);
}
void filter_ips(lt::session& ses)
{
ip_filter filter;
filter.add_rule(address_v4::from_string("50.0.0.1")
, address_v4::from_string("50.0.0.2"), ip_filter::blocked);
ses.set_ip_filter(filter);
}
void set_cache_size(lt::session& ses, int val)
{
settings_pack pack;
pack.set_int(settings_pack::cache_size, val);
ses.apply_settings(pack);
}
int get_cache_size(lt::session& ses)
{
std::vector<stats_metric> stats = session_stats_metrics();
int const read_cache_idx = find_metric_idx("disk.read_cache_blocks");
int const write_cache_idx = find_metric_idx("disk.write_cache_blocks");
TEST_CHECK(read_cache_idx >= 0);
TEST_CHECK(write_cache_idx >= 0);
ses.set_alert_notify([](){});
ses.post_session_stats();
std::vector<alert*> alerts;
ses.pop_alerts(&alerts);
int cache_size = -1;
for (auto const a : alerts)
{
if (auto const* st = alert_cast<session_stats_alert>(a))
{
cache_size = st->values[read_cache_idx];
cache_size += st->values[write_cache_idx];
break;
}
}
return cache_size;
}
void set_proxy(lt::session& ses, int proxy_type, int flags, bool proxy_peer_connections)
{
// apply the proxy settings to session 0
settings_pack p;
p.set_int(settings_pack::proxy_type, proxy_type);
if (proxy_type == settings_pack::socks4)
p.set_int(settings_pack::proxy_port, 4444);
else
p.set_int(settings_pack::proxy_port, 5555);
if (flags & ipv6)
p.set_str(settings_pack::proxy_hostname, "2001::2");
else
p.set_str(settings_pack::proxy_hostname, "50.50.50.50");
p.set_bool(settings_pack::proxy_hostnames, true);
p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections);
p.set_bool(settings_pack::proxy_tracker_connections, true);
ses.apply_settings(p);
}
void print_alerts(lt::session& ses
, std::function<void(lt::session&, lt::alert const*)> on_alert)
{
lt::time_point start_time = lt::clock_type::now();
ses.set_alert_notify([&ses,start_time,on_alert] {
ses.get_io_service().post([&ses,start_time,on_alert] {
std::vector<lt::alert*> alerts;
ses.pop_alerts(&alerts);
for (lt::alert const* a : alerts)
{
printf("%-3d [0] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
// call the user handler
on_alert(ses, a);
}
} ); } );
}

60
simulation/utils.hpp Normal file
View File

@ -0,0 +1,60 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <functional>
namespace libtorrent
{
class session;
class alert;
}
namespace lt = libtorrent;
void utp_only(lt::session& ses);
void enable_enc(lt::session& ses);
void filter_ips(lt::session& ses);
void set_cache_size(lt::session& ses, int val);
int get_cache_size(lt::session& ses);
enum flags_t
{
ipv6 = 1,
};
void set_proxy(lt::session& ses, int proxy_type, int flags = 0
, bool proxy_peer_connections = true);
void print_alerts(lt::session& ses
, std::function<void(lt::session&, lt::alert const*)> on_alert
= [](lt::session& ses, lt::alert const* a) {});

View File

@ -3741,7 +3741,8 @@ retry:
t->log_to_all_peers("auto manager pausing torrent"); t->log_to_all_peers("auto manager pausing torrent");
#endif #endif
// use graceful pause for auto-managed torrents // use graceful pause for auto-managed torrents
t->set_allow_peers(false, true); t->set_allow_peers(false, torrent::flag_graceful_pause
| torrent::flag_clear_disk_cache);
t->set_announce_to_dht(false); t->set_announce_to_dht(false);
t->set_announce_to_trackers(false); t->set_announce_to_trackers(false);
t->set_announce_to_lsd(false); t->set_announce_to_lsd(false);

View File

@ -2879,7 +2879,9 @@ namespace libtorrent
{ {
// if we're auto managed. assume we need to be paused until the auto // if we're auto managed. assume we need to be paused until the auto
// managed logic runs again (which is triggered further down) // managed logic runs again (which is triggered further down)
pause(); // setting flags to 0 prevents the disk cache from being evicted as a
// result of this
set_allow_peers(false, 0);
} }
// we're done checking! (this should cause a call to trigger_auto_manage) // we're done checking! (this should cause a call to trigger_auto_manage)
@ -9706,10 +9708,11 @@ namespace libtorrent
set_need_save_resume(); set_need_save_resume();
} }
set_allow_peers(false, graceful); int const flags = graceful ? flag_graceful_pause : 0;
set_allow_peers(false, flags | flag_clear_disk_cache);
} }
void torrent::do_pause() void torrent::do_pause(bool const clear_disk_cache)
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
if (!is_paused()) return; if (!is_paused()) return;
@ -9773,7 +9776,7 @@ namespace libtorrent
{ {
// this will make the storage close all // this will make the storage close all
// files and flush all cached data // files and flush all cached data
if (m_storage.get()) if (m_storage.get() && clear_disk_cache)
{ {
TORRENT_ASSERT(m_storage); TORRENT_ASSERT(m_storage);
m_ses.disk_thread().async_stop_torrent(m_storage.get() m_ses.disk_thread().async_stop_torrent(m_storage.get()
@ -9873,7 +9876,7 @@ namespace libtorrent
set_need_save_resume(); set_need_save_resume();
} }
void torrent::set_allow_peers(bool b, bool graceful) void torrent::set_allow_peers(bool b, int flags)
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
@ -9883,7 +9886,7 @@ namespace libtorrent
// if there are no peers, we must not enter graceful pause mode, and post // if there are no peers, we must not enter graceful pause mode, and post
// the torrent_paused_alert immediately instead. // the torrent_paused_alert immediately instead.
if (m_connections.empty()) if (m_connections.empty())
graceful = false; flags &= ~flag_graceful_pause;
if (m_allow_peers == b) if (m_allow_peers == b)
{ {
@ -9892,9 +9895,9 @@ namespace libtorrent
// paused mode, we need to actually pause the torrent properly // paused mode, we need to actually pause the torrent properly
if (m_allow_peers == false if (m_allow_peers == false
&& m_graceful_pause_mode == true && m_graceful_pause_mode == true
&& graceful == false) && (flags & flag_graceful_pause) == 0)
{ {
m_graceful_pause_mode = graceful; m_graceful_pause_mode = false;
update_gauge(); update_gauge();
do_pause(); do_pause();
} }
@ -9903,7 +9906,7 @@ namespace libtorrent
m_allow_peers = b; m_allow_peers = b;
if (!m_ses.is_paused()) if (!m_ses.is_paused())
m_graceful_pause_mode = graceful; m_graceful_pause_mode = (flags & flag_graceful_pause) ? true : false;
if (!b) if (!b)
{ {
@ -9920,7 +9923,7 @@ namespace libtorrent
if (!b) if (!b)
{ {
do_pause(); do_pause(flags & flag_clear_disk_cache);
} }
else else
{ {