From f5d5ac4f3a64493798001e2aa43cac1699a5bd16 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 6 Mar 2016 21:42:18 -0500 Subject: [PATCH] fix bug where disk cache was wiped out after completion file-checking. factor out sim test utilities and reuse them in the regression test --- include/libtorrent/torrent.hpp | 10 ++- simulation/Jamfile | 2 + simulation/test_checking.cpp | 115 +++++++++++++++++++++++++++ simulation/test_transfer.cpp | 116 ++------------------------- simulation/utils.cpp | 139 +++++++++++++++++++++++++++++++++ simulation/utils.hpp | 60 ++++++++++++++ src/session_impl.cpp | 3 +- src/torrent.cpp | 23 +++--- test/test_checking.cpp | 2 +- 9 files changed, 347 insertions(+), 123 deletions(-) create mode 100644 simulation/test_checking.cpp create mode 100644 simulation/utils.cpp create mode 100644 simulation/utils.hpp diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 68e9493b7..48c5e6c08 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -459,7 +459,13 @@ namespace libtorrent void flush_cache(); void pause(bool graceful = false); 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_trackers(bool b) { m_announce_to_trackers = 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; } void step_session_time(int seconds); - void do_pause(); + void do_pause(bool clear_disk_cache = true); void do_resume(); int finished_time() const; diff --git a/simulation/Jamfile b/simulation/Jamfile index 4e99da0f9..5a32e0da7 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -15,6 +15,7 @@ project setup_swarm.cpp setup_dht.cpp create_torrent.cpp + utils.cpp : default-build multi full @@ -23,6 +24,7 @@ project ; alias libtorrent-sims : + [ run test_checking.cpp ] [ run test_optimistic_unchoke.cpp ] [ run test_transfer.cpp ] [ run test_http_connection.cpp ] diff --git a/simulation/test_checking.cpp b/simulation/test_checking.cpp new file mode 100644 index 000000000..87d27a3ca --- /dev/null +++ b/simulation/test_checking.cpp @@ -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 +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(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(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 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 tor = ses.get_torrents(); + TEST_EQUAL(tor.size(), 1); + + TEST_EQUAL(tor[0].status().is_seeding, true); + }); +} diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index ddae108ba..07f948dcb 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -45,16 +45,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "simulator/simulator.hpp" #include "simulator/socks_server.hpp" #include "setup_swarm.hpp" +#include "utils.hpp" using namespace sim; namespace lt = libtorrent; -enum flags_t -{ - ipv6 = 1, -}; - template void run_test( Setup const& setup @@ -64,8 +60,6 @@ void run_test( { using namespace libtorrent; - lt::time_point start_time = lt::clock_type::now(); - const bool use_ipv6 = flags & ipv6; 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]); // only monitor alerts for session 0 (the downloader) - ses[0]->set_alert_notify([&] { ios0.post([&] { - std::vector alerts; - ses[0]->pop_alerts(&alerts); - - for (lt::alert const* a : alerts) + print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) { + if (auto ta = alert_cast(a)) { - printf("%-3d [0] %s\n", int(lt::duration_cast(a->timestamp() - - start_time).count()), a->message().c_str()); - if (auto ta = alert_cast(a)) - { - ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); - } - // call the user handler - on_alert(*ses[0], a); + ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); } - } ); } ); + on_alert(ses, a); + }); - ses[1]->set_alert_notify([&] { ios0.post([&] { - std::vector alerts; - ses[1]->pop_alerts(&alerts); - for (lt::alert const* a : alerts) - { - printf("%-3d [1] %s\n", int(lt::duration_cast(a->timestamp() - - start_time).count()), a->message().c_str()); - } - } ); } ); + print_alerts(*ses[1]); // the first peer is a downloader, the second peer is a seed lt::add_torrent_params params = create_torrent(1); @@ -170,85 +147,6 @@ void run_test( 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 = 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 alerts; - ses.pop_alerts(&alerts); - int cache_size = -1; - for (auto const a : alerts) - { - if (auto const* st = alert_cast(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) { using namespace libtorrent; diff --git a/simulation/utils.cpp b/simulation/utils.cpp new file mode 100644 index 000000000..e8d007205 --- /dev/null +++ b/simulation/utils.cpp @@ -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 = 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 alerts; + ses.pop_alerts(&alerts); + int cache_size = -1; + for (auto const a : alerts) + { + if (auto const* st = alert_cast(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 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 alerts; + ses.pop_alerts(&alerts); + + for (lt::alert const* a : alerts) + { + printf("%-3d [0] %s\n", int(lt::duration_cast(a->timestamp() + - start_time).count()), a->message().c_str()); + // call the user handler + on_alert(ses, a); + } + } ); } ); +} + diff --git a/simulation/utils.hpp b/simulation/utils.hpp new file mode 100644 index 000000000..26cfbf96e --- /dev/null +++ b/simulation/utils.hpp @@ -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 + +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 on_alert + = [](lt::session& ses, lt::alert const* a) {}); + diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 510f0fb66..b38567f83 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -3741,7 +3741,8 @@ retry: t->log_to_all_peers("auto manager pausing torrent"); #endif // 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_trackers(false); t->set_announce_to_lsd(false); diff --git a/src/torrent.cpp b/src/torrent.cpp index b9c99794c..7b11f071f 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -2879,7 +2879,9 @@ namespace libtorrent { // if we're auto managed. assume we need to be paused until the auto // 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) @@ -9706,10 +9708,11 @@ namespace libtorrent 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()); if (!is_paused()) return; @@ -9773,7 +9776,7 @@ namespace libtorrent { // this will make the storage close all // files and flush all cached data - if (m_storage.get()) + if (m_storage.get() && clear_disk_cache) { TORRENT_ASSERT(m_storage); m_ses.disk_thread().async_stop_torrent(m_storage.get() @@ -9873,7 +9876,7 @@ namespace libtorrent 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()); @@ -9883,7 +9886,7 @@ namespace libtorrent // if there are no peers, we must not enter graceful pause mode, and post // the torrent_paused_alert immediately instead. if (m_connections.empty()) - graceful = false; + flags &= ~flag_graceful_pause; if (m_allow_peers == b) { @@ -9892,9 +9895,9 @@ namespace libtorrent // paused mode, we need to actually pause the torrent properly if (m_allow_peers == false && m_graceful_pause_mode == true - && graceful == false) + && (flags & flag_graceful_pause) == 0) { - m_graceful_pause_mode = graceful; + m_graceful_pause_mode = false; update_gauge(); do_pause(); } @@ -9903,7 +9906,7 @@ namespace libtorrent m_allow_peers = b; if (!m_ses.is_paused()) - m_graceful_pause_mode = graceful; + m_graceful_pause_mode = (flags & flag_graceful_pause) ? true : false; if (!b) { @@ -9920,7 +9923,7 @@ namespace libtorrent if (!b) { - do_pause(); + do_pause(flags & flag_clear_disk_cache); } else { diff --git a/test/test_checking.cpp b/test/test_checking.cpp index d19386a9d..f78f3b04b 100644 --- a/test/test_checking.cpp +++ b/test/test_checking.cpp @@ -94,7 +94,7 @@ void test_checking(int flags = read_only_files) create_directory(combine_path("tmp1_checking", "test_torrent_dir"), ec); if (ec) fprintf(stderr, "ERROR: creating directory test_torrent_dir: (%d) %s\n" , ec.value(), ec.message().c_str()); - + file_storage fs; std::srand(10); int piece_size = 0x4000;