fix multible torrent status timer bugs related to move time (#1492)

fix last_upload and last_download overflow after 9 hours in past. change last_upload, last_download, finished_time,  resume, upload_mode_time to time_point and duration
This commit is contained in:
Falcosc 2017-02-04 19:34:14 +01:00 committed by Arvid Norberg
parent 3ef4109bf3
commit a9d6d54111
6 changed files with 398 additions and 123 deletions

View File

@ -1,3 +1,4 @@
* fix last_upload and last_download overflow after 9 hours in past
* python binding add more add_torrent_params fields and an invalid key check
* introduce introduce distinct types for peer_class_t, piece_index_t and
file_index_t.

View File

@ -5,6 +5,7 @@ import libtorrent as lt
import unittest
import time
import datetime
import os
import shutil
import binascii
@ -80,6 +81,18 @@ class test_torrent_handle(unittest.TestCase):
self.setup()
self.h.clear_piece_deadlines()
def test_status_last_uploaded_dowloaded(self):
# we want to check at seconds precision but can't control session
# time, wait for next full second to prevent second increment
time.sleep(1 - datetime.datetime.now().microsecond / 1000000.0)
sessionStart = datetime.datetime.now().replace(microsecond=0)
self.setup()
st = self.h.status()
# last upload and download times are at session start time
self.assertEqual(st.last_upload, sessionStart)
self.assertEqual(st.last_download, sessionStart)
def test_torrent_status(self):
self.setup()
st = self.h.status()
@ -268,6 +281,7 @@ class test_alerts(unittest.TestCase):
'enable_dht': False})
ses.async_add_torrent(
{"ti": lt.torrent_info("base.torrent"), "save_path": "."})
# this will cause an error (because of duplicate torrents) and the
# torrent_info object created here will be deleted once the alert goes out
# of scope. When that happens, it will decrement the python object, to allow

View File

@ -95,6 +95,8 @@ namespace libtorrent
class bt_peer_connection;
struct listen_socket_t;
using seconds32 = std::chrono::duration<std::int32_t>;
enum class waste_reason
{
piece_timed_out, piece_cancelled, piece_unknown, piece_seed
@ -478,14 +480,15 @@ namespace libtorrent
void stop_when_ready(bool b);
int started() const { return m_started; }
time_point started() const { return m_started; }
void step_session_time(int seconds);
void do_pause(bool clear_disk_cache = true);
void do_resume();
int finished_time() const;
int active_time() const;
int seeding_time() const;
seconds32 finished_time() const;
seconds32 active_time() const;
seconds32 seeding_time() const;
seconds32 upload_mode_time() const;
bool is_paused() const;
bool is_torrent_paused() const { return m_paused; }
@ -496,7 +499,8 @@ namespace libtorrent
{
// save resume data every 15 minutes regardless, just to
// keep stats up to date
return m_need_save_resume_data || m_ses.session_time() - m_last_saved_resume > 15 * 60;
return m_need_save_resume_data ||
aux::time_now() - m_last_saved_resume > minutes(15);
}
void set_need_save_resume()
@ -1034,7 +1038,7 @@ namespace libtorrent
// that are not private
void lsd_announce();
void update_last_upload() { m_last_upload = int16_t(m_ses.session_time()); }
void update_last_upload() { m_last_upload = aux::time_now(); }
void set_apply_ip_filter(bool b);
bool apply_ip_filter() const { return m_apply_ip_filter; }
@ -1314,9 +1318,7 @@ namespace libtorrent
// m_num_verified = m_verified.count()
std::uint32_t m_num_verified = 0;
// this timestamp is kept in session-time, to
// make it fit in 16 bits
std::uint16_t m_last_saved_resume;
time_point m_last_saved_resume = aux::time_now();
// if this torrent is running, this was the time
// when it was started. This is used to have a
@ -1326,15 +1328,15 @@ namespace libtorrent
// in session-time. see session_impl for details.
// the reference point is stepped forward every 4
// hours to keep the timestamps fit in 16 bits
std::uint16_t m_started;
time_point m_started = aux::time_now();
// if we're a seed, this is the session time
// timestamp of when we became one
std::uint16_t m_became_seed = 0;
time_point m_became_seed = aux::time_now();
// if we're finished, this is the session time
// timestamp of when we finished
std::uint16_t m_became_finished = 0;
time_point m_became_finished = aux::time_now();
// when checking, this is the first piece we have not
// issued a hash job for
@ -1383,7 +1385,7 @@ namespace libtorrent
// the session time timestamp of when we entered upload mode
// if we're currently in upload-mode
std::uint16_t m_upload_mode_time = 0;
time_point m_upload_mode_time = aux::time_now();
// true when this torrent should announce to
// trackers
@ -1425,7 +1427,7 @@ namespace libtorrent
// paused. specified in seconds. This only track time _before_ we started
// the torrent this last time. When the torrent is paused, this counter is
// incremented to include this current session.
unsigned int m_active_time:24;
seconds32 m_active_time;
// the index to the last tracker that worked
std::int8_t m_last_working_tracker = -1;
@ -1434,7 +1436,7 @@ namespace libtorrent
// total time we've been finished with this torrent.
// does not count when the torrent is stopped or paused.
unsigned int m_finished_time:24;
seconds32 m_finished_time;
// in case the piece picker hasn't been constructed
// when this settings is set, this variable will keep
@ -1474,7 +1476,7 @@ namespace libtorrent
// accounts for the time prior to the current start of the torrent. When
// the torrent is paused, this counter is incremented to account for the
// additional seeding time.
unsigned int m_seeding_time:24;
seconds32 m_seeding_time;
// ----
@ -1562,7 +1564,7 @@ namespace libtorrent
// the timestamp of the last piece passed for this torrent specified in
// session_time. This is signed because it must be able to represent time
// before the session started
std::int16_t m_last_download = (std::numeric_limits<std::int16_t>::min)();
time_point m_last_download = aux::time_now();
// the number of peer connections to seeds. This should be the same as
// counting the peer connections that say true for is_seed()
@ -1575,7 +1577,7 @@ namespace libtorrent
// the timestamp of the last byte uploaded from this torrent specified in
// session_time. This is signed because it must be able to represent time
// before the session started.
std::int16_t m_last_upload = (std::numeric_limits<std::int16_t>::min)();
time_point m_last_upload = aux::time_now();
// ----

View File

@ -546,7 +546,9 @@ namespace libtorrent
// the info-hash for this torrent
sha1_hash info_hash;
// This value is not persistent and get set to session start time.
time_point last_upload;
// This value is not persistent and get set to session start time.
time_point last_download;
seconds active_duration;

View File

@ -79,24 +79,294 @@ TORRENT_TEST(status_timers)
if ((ticks % 3600) == 0)
{
lt::time_point const now = lt::clock_type::now();
auto const since_start = duration_cast<seconds>(now - start_time) - lt::seconds(1);
// finish is 1 tick after start
auto const since_finish = duration_cast<seconds>(now - start_time) - lt::seconds(1);
torrent_status st = handle.status();
TEST_CHECK(st.active_duration == since_start);
TEST_CHECK(st.seeding_duration == since_start);
TEST_CHECK(st.finished_duration == since_start);
TEST_CHECK(st.last_upload < start_time);
TEST_EQUAL(st.active_duration.count(), since_finish.count());
TEST_EQUAL(st.seeding_duration.count(), since_finish.count());
TEST_EQUAL(st.finished_duration.count(), since_finish.count());
// checking the torrent counts as downloading
// eventually though, we've forgotten about it and go back to -1
if (since_start > lt::seconds(65000))
{
TEST_CHECK(st.last_download < start_time);
// does not upload without peers
TEST_CHECK(st.last_upload == start_time);
// does not download in seeding mode
TEST_CHECK(st.last_download == start_time);
}
else
{
// TODO: this should really be a proximity-check
TEST_CHECK(st.last_download == start_time + lt::seconds(1));
return false;
});
TEST_CHECK(ran_to_completion);
}
TORRENT_TEST(status_timers_last_upload)
{
bool ran_to_completion = false;
lt::time_point start_time;
lt::torrent_handle handle;
setup_swarm(2, swarm_test::upload
// add session
, [](lt::settings_pack&) {}
// add torrent
, [](lt::add_torrent_params&) {}
// on alert
, [&](lt::alert const* a, lt::session&) {
if (auto ta = alert_cast<torrent_added_alert>(a))
{
TEST_CHECK(!handle.is_valid());
start_time = lt::clock_type::now();
handle = ta->handle;
torrent_status st = handle.status();
// test last upload and download state before wo go throgh
// torrent states
TEST_CHECK(st.last_download == start_time);
TEST_CHECK(st.last_upload == start_time);
}
}
// terminate
, [&](int ticks, lt::session&) -> bool
{
if (ticks > 10)
{
ran_to_completion = true;
return true;
}
torrent_status st = handle.status();
// uploadtime is 0 seconds behind now
TEST_EQUAL(duration_cast<seconds>(st.last_upload - lt::clock_type::now()).count(), 0);
// does not download in seeding mode
TEST_CHECK(st.last_download == start_time);
return false;
});
TEST_CHECK(ran_to_completion);
}
TORRENT_TEST(status_timers_time_shift_with_active_torrent)
{
bool ran_to_completion = false;
lt::time_point start_time;
lt::torrent_handle handle;
seconds expected_active_duration = seconds(0);
bool tick_is_in_active_range = false;
int tick_check_intervall = 1;
setup_swarm(1, swarm_test::upload
// add session
, [](lt::settings_pack&) {}
// add torrent
, [](lt::add_torrent_params&) {}
// on alert
, [&](lt::alert const* a, lt::session&) {
if (auto ta = alert_cast<torrent_added_alert>(a))
{
TEST_CHECK(!handle.is_valid());
start_time = lt::clock_type::now();
handle = ta->handle;
torrent_status st = handle.status();
// test last upload and download state before wo go throgh
// torrent states
TEST_CHECK(st.last_download == start_time);
TEST_CHECK(st.last_upload == start_time);
}
}
// terminate
, [&](int ticks, lt::session&) -> bool
{
if(tick_is_in_active_range){
// 1 second per tick
expected_active_duration++;
}
switch(ticks)
{
case 0:
// torrent get ready for seeding on first tick, means time +1s
tick_is_in_active_range = true;
break;
case 1:
// pause after we did have the first upload tick
handle.pause();
tick_is_in_active_range = false;
break;
case 64000:
// resume just before we hit the time shift handling
// this is needed to test what happend if we want to
// shift more time then we have active time because
// we shift 4 hours and have less then 1 hours active time
handle.resume();
tick_is_in_active_range = true;
// don't check every tick
tick_check_intervall = 600;
break;
case 68000:
// simulate at least 68000 seconds because timestamps are
// 16 bits counting seconds
ran_to_completion = true;
return true;
}
// verify that the timers seem correct
if (tick_is_in_active_range && (ticks % tick_check_intervall) == 0)
{
torrent_status st = handle.status();
TEST_EQUAL(st.active_duration.count(), expected_active_duration.count());
TEST_EQUAL(st.seeding_duration.count(), expected_active_duration.count());
TEST_EQUAL(st.finished_duration.count(), expected_active_duration.count());
// does not upload without peers
TEST_CHECK(st.last_upload == start_time);
// does not download in seeding mode
TEST_CHECK(st.last_download == start_time);
}
return false;
});
TEST_CHECK(ran_to_completion);
}
TORRENT_TEST(finish_time_shift_active)
{
bool ran_to_completion = false;
lt::time_point start_time;
lt::torrent_handle handle;
seconds expected_active_duration = seconds(0);
bool tick_is_in_active_range = false;
setup_swarm(1, swarm_test::upload
// add session
, [](lt::settings_pack&) {}
// add torrent
, [](lt::add_torrent_params&) {}
// on alert
, [&](lt::alert const* a, lt::session&) {
if (auto ta = alert_cast<torrent_added_alert>(a))
{
TEST_CHECK(!handle.is_valid());
start_time = lt::clock_type::now();
handle = ta->handle;
torrent_status st = handle.status();
// test last upload and download state before wo go throgh
// torrent states
TEST_CHECK(st.last_download == start_time);
TEST_CHECK(st.last_upload == start_time);
}
}
// terminate
, [&](int ticks, lt::session&) -> bool
{
if(tick_is_in_active_range){
// 1 second per tick
expected_active_duration++;
}
switch(ticks)
{
case 0:
// torrent get ready for seeding on first tick, means time +1s
tick_is_in_active_range = true;
break;
case 7000:
// pause before 4 hours to get a become finish timestamp which
// will be clamped
handle.pause();
// resume to get an become finish update
handle.resume();
tick_is_in_active_range = true;
break;
case 70000:
// simulate at least 70000 seconds because timestamps are
// 16 bits counting seconds
ran_to_completion = true;
return true;
}
// verify that the timers seem correct
if ((ticks % 3600) == 0)
{
torrent_status st = handle.status();
TEST_EQUAL(st.active_duration.count(), expected_active_duration.count());
TEST_EQUAL(st.seeding_duration.count(), expected_active_duration.count());
TEST_EQUAL(st.finished_duration.count(), expected_active_duration.count());
// does not upload without peers
TEST_CHECK(st.last_upload == start_time);
// does not download in seeding mode
TEST_CHECK(st.last_download == start_time);
}
return false;
});
TEST_CHECK(ran_to_completion);
}
TORRENT_TEST(finish_time_shift_paused)
{
bool ran_to_completion = false;
lt::time_point start_time;
lt::torrent_handle handle;
seconds expected_active_duration = seconds(0);
bool tick_is_in_active_range = false;
setup_swarm(1, swarm_test::upload
// add session
, [](lt::settings_pack&) {}
// add torrent
, [](lt::add_torrent_params&) {}
// on alert
, [&](lt::alert const* a, lt::session&) {
if (auto ta = alert_cast<torrent_added_alert>(a))
{
TEST_CHECK(!handle.is_valid());
start_time = lt::clock_type::now();
handle = ta->handle;
torrent_status st = handle.status();
// test last upload and download state before wo go throgh
// torrent states
TEST_CHECK(st.last_download == start_time);
TEST_CHECK(st.last_upload == start_time);
}
}
// terminate
, [&](int ticks, lt::session&) -> bool
{
if(tick_is_in_active_range){
// 1 second per tick
expected_active_duration++;
}
switch(ticks)
{
case 0:
// torrent get ready for seeding on first tick, means time +1s
tick_is_in_active_range = true;
break;
case 7000:
// pause before 4 hours to get a become finish timestamp which
// will be clamped
handle.pause();
// resume to get an become finish update
handle.resume();
// pause to test timeshift in paused state
handle.pause();
tick_is_in_active_range = false;
break;
case 70000:
// simulate at least 70000 seconds because timestamps are
// 16 bits counting seconds
ran_to_completion = true;
return true;
}
// verify that the timers seem correct
if (tick_is_in_active_range && (ticks % 3600) == 0)
{
torrent_status st = handle.status();
TEST_EQUAL(st.active_duration.count(), expected_active_duration.count());
TEST_EQUAL(st.seeding_duration.count(), expected_active_duration.count());
TEST_EQUAL(st.finished_duration.count(), expected_active_duration.count());
// does not upload without peers
TEST_CHECK(st.last_upload == start_time);
// does not download in seeding mode
TEST_CHECK(st.last_download == start_time);
}
return false;
});

View File

@ -102,6 +102,9 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
using namespace std::placeholders;
using std::chrono::duration_cast;
using std::chrono::seconds;
using libtorrent::seconds32;
namespace libtorrent
{
@ -121,7 +124,6 @@ namespace libtorrent
}
return ret;
}
constexpr int default_piece_priority = 4;
} // anonymous namespace
@ -180,8 +182,8 @@ namespace libtorrent
, m_storage_constructor(p.storage)
, m_added_time(time(nullptr))
, m_info_hash(info_hash)
, m_last_saved_resume(ses.session_time())
, m_started(ses.session_time())
, m_last_saved_resume(aux::time_now())
, m_started(aux::time_now())
, m_error_file(torrent_status::error_file_none)
, m_sequence_number(seq)
, m_announce_to_trackers((p.flags & add_torrent_params::flag_paused) == 0)
@ -373,9 +375,9 @@ namespace libtorrent
// the number of seconds this torrent has spent in started, finished and
// seeding state so far, respectively.
m_active_time = p.active_time;
m_finished_time = p.finished_time;
m_seeding_time = p.seeding_time;
m_active_time = seconds(p.active_time);
m_finished_time = seconds(p.finished_time);
m_seeding_time = seconds(p.seeding_time);
m_added_time = p.added_time ? p.added_time : time(nullptr);
m_completed_time = p.completed_time;
@ -961,7 +963,7 @@ namespace libtorrent
p->cancel_all_requests();
}
// this is used to try leaving upload only mode periodically
m_upload_mode_time = m_ses.session_time();
m_upload_mode_time = aux::time_now();
}
else if (m_peer_list)
{
@ -3849,7 +3851,7 @@ namespace libtorrent
// is deallocated by the torrent once it starts seeding
}
m_last_download = m_ses.session_time();
m_last_download = aux::time_now();
if (m_share_mode)
recalc_share_mode();
@ -5950,9 +5952,10 @@ namespace libtorrent
ret["total_uploaded"] = m_total_uploaded;
ret["total_downloaded"] = m_total_downloaded;
ret["active_time"] = active_time();
ret["finished_time"] = finished_time();
ret["seeding_time"] = seeding_time();
// cast to seconds in case that internal values doesn't have ratio<1>
ret["active_time"] = duration_cast<seconds>(active_time()).count();
ret["finished_time"] = duration_cast<seconds>(finished_time()).count();
ret["seeding_time"] = duration_cast<seconds>(seeding_time()).count();
ret["last_seen_complete"] = m_last_seen_complete;
ret["num_complete"] = m_complete;
@ -7241,7 +7244,7 @@ namespace libtorrent
set_state(torrent_status::finished);
set_queue_position(-1);
m_became_finished = m_ses.session_time();
m_became_finished = aux::time_now();
// we have to call completed() before we start
// disconnecting peers, since there's an assert
@ -7358,7 +7361,7 @@ namespace libtorrent
maybe_done_flushing();
set_state(torrent_status::seeding);
m_became_seed = m_ses.session_time();
m_became_seed = aux::time_now();
if (!m_announcing) return;
@ -8220,14 +8223,14 @@ namespace libtorrent
if (a < b) return 0;
return std::uint16_t(a - b);
}
#ifndef TORRENT_NO_DEPRECATE
std::int16_t clamped_subtract_s16(int a, int b)
{
if (a + (std::numeric_limits<std::int16_t>::min)() < b)
return (std::numeric_limits<std::int16_t>::min)();
return std::int16_t(a - b);
}
#endif
} // anonymous namespace
// this is called every time the session timer takes a step back. Since the
@ -8249,44 +8252,9 @@ namespace libtorrent
}
}
// m_active_time, m_seeding_time and m_finished_time are absolute counters
// of the historical time we've spent in each state. The current time
// we've spent in those states (this session) is calculated by
// session_time() - m_started
// session_time() - m_became_seed
// session_time() - m_became_finished respectively. If any of the
// comparison points were pulled back to the oldest representable value (0)
// the left-over time must be transferred into the m_*_time counters.
if (m_started < seconds && !is_paused())
{
int const lost_seconds = seconds - m_started;
m_active_time += lost_seconds;
}
m_started = clamped_subtract_u16(m_started, seconds);
if (m_became_seed < seconds && is_seed())
{
int const lost_seconds = seconds - m_became_seed;
m_seeding_time += lost_seconds;
}
m_became_seed = clamped_subtract_u16(m_became_seed, seconds);
if (m_became_finished < seconds && is_finished())
{
int const lost_seconds = seconds - m_became_finished;
m_finished_time += lost_seconds;
}
m_became_finished = clamped_subtract_u16(m_became_finished, seconds);
m_last_upload = clamped_subtract_s16(m_last_upload, seconds);
m_last_download = clamped_subtract_s16(m_last_download, seconds);
#ifndef TORRENT_NO_DEPRECATE
m_last_scrape = clamped_subtract_s16(m_last_scrape, seconds);
#endif
m_last_saved_resume = clamped_subtract_u16(m_last_saved_resume, seconds);
m_upload_mode_time = clamped_subtract_u16(m_upload_mode_time, seconds);
}
// the higher seed rank, the more important to seed
@ -8308,15 +8276,16 @@ namespace libtorrent
int ret = 0;
std::int64_t const fin_time = finished_time();
std::int64_t const download_time = int(active_time()) - fin_time;
seconds32 const act_time = active_time();
seconds32 const fin_time = finished_time();
seconds32 const download_time = act_time - fin_time;
// if we haven't yet met the seed limits, set the seed_ratio_not_met
// flag. That will make this seed prioritized
// downloaded may be 0 if the torrent is 0-sized
std::int64_t const downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
if (fin_time < s.get_int(settings_pack::seed_time_limit)
&& (download_time > 1
if (fin_time < seconds(s.get_int(settings_pack::seed_time_limit))
&& (download_time.count() > 1
&& fin_time * 100 / download_time < s.get_int(settings_pack::seed_time_ratio_limit))
&& downloaded > 0
&& m_total_uploaded * 100 / downloaded < s.get_int(settings_pack::share_ratio_limit))
@ -8324,7 +8293,7 @@ namespace libtorrent
// if this torrent is running, and it was started less
// than 30 minutes ago, give it priority, to avoid oscillation
if (!is_paused() && (m_ses.session_time() - m_started) < 30 * 60)
if (!is_paused() && act_time < minutes(30))
ret |= recently_started;
// if we have any scrape data, use it to calculate
@ -8375,7 +8344,7 @@ namespace libtorrent
}
m_need_save_resume_data = false;
m_last_saved_resume = m_ses.session_time();
m_last_saved_resume = aux::time_now();
m_save_resume_flags = std::uint8_t(flags);
state_updated();
@ -8472,13 +8441,16 @@ namespace libtorrent
update_state_list();
update_want_tick();
m_active_time += m_ses.session_time() - m_started;
const time_point now = aux::time_now();
if (is_seed())
m_seeding_time += m_ses.session_time() - m_became_seed;
m_active_time +=
duration_cast<seconds32>(now - m_started);
if (is_finished())
m_finished_time += m_ses.session_time() - m_became_finished;
if (is_seed()) m_seeding_time +=
duration_cast<seconds32>(now - m_became_seed);
if (is_finished()) m_finished_time +=
duration_cast<seconds32>(now - m_became_finished);
m_announce_to_dht = false;
m_announce_to_trackers = false;
@ -8704,7 +8676,7 @@ namespace libtorrent
if (alerts().should_post<torrent_resumed_alert>())
alerts().emplace_alert<torrent_resumed_alert>(get_handle());
m_started = m_ses.session_time();
m_started = aux::time_now();
if (is_seed()) m_became_seed = m_started;
if (is_finished()) m_became_finished = m_started;
@ -8893,31 +8865,45 @@ namespace libtorrent
announce_with_tracker(tracker_request::stopped);
}
int torrent::finished_time() const
seconds32 torrent::finished_time() const
{
// m_finished_time does not account for the current "session", just the
// time before we last started this torrent. To get the current time, we
// need to add the time since we started it
return m_finished_time + ((!is_finished() || is_paused()) ? 0
: (m_ses.session_time() - m_became_finished));
if(!is_finished() || is_paused())
return m_finished_time;
return m_finished_time + duration_cast<seconds32>(
aux::time_now() - m_became_finished);
}
int torrent::active_time() const
seconds32 torrent::active_time() const
{
if(is_paused())
return m_active_time;
// m_active_time does not account for the current "session", just the
// time before we last started this torrent. To get the current time, we
// need to add the time since we started it
return m_active_time + (is_paused() ? 0
: m_ses.session_time() - m_started);
return m_active_time + duration_cast<seconds32>(
aux::time_now() - m_started);
}
int torrent::seeding_time() const
seconds32 torrent::seeding_time() const
{
if(!is_seed() || is_paused())
return m_seeding_time;
// m_seeding_time does not account for the current "session", just the
// time before we last started this torrent. To get the current time, we
// need to add the time since we started it
return m_seeding_time + ((!is_seed() || is_paused()) ? 0
: m_ses.session_time() - m_became_seed);
return m_seeding_time + duration_cast<seconds32>(
aux::time_now() - m_became_seed);
}
seconds32 torrent::upload_mode_time() const
{
if(!m_upload_mode)
return seconds32(0);
return duration_cast<seconds32>(
aux::time_now() - m_upload_mode_time);
}
void torrent::second_tick(int tick_interval_ms)
@ -8940,9 +8926,8 @@ namespace libtorrent
// if we're in upload only mode and we're auto-managed
// leave upload mode every 10 minutes hoping that the error
// condition has been fixed
if (m_upload_mode && m_auto_managed
&& int(m_ses.session_time() - m_upload_mode_time)
>= settings().get_int(settings_pack::optimistic_disk_retry))
if (m_upload_mode && m_auto_managed && upload_mode_time() >=
seconds(settings().get_int(settings_pack::optimistic_disk_retry)))
{
set_upload_mode(false);
}
@ -10580,22 +10565,23 @@ namespace libtorrent
// activity time
#ifndef TORRENT_NO_DEPRECATE
st->finished_time = finished_time();
st->active_time = active_time();
st->seeding_time = seeding_time();
// cast to seconds in case that internal values doesn't have ratio<1>
st->finished_time = int(duration_cast<seconds>(finished_time()).count());
st->active_time = int(duration_cast<seconds>(active_time()).count());
st->seeding_time = int(duration_cast<seconds>(seeding_time()).count());
st->time_since_upload = m_last_upload == (std::numeric_limits<std::int16_t>::min)() ? -1
: clamped_subtract_u16(m_ses.session_time(), m_last_upload);
st->time_since_download = m_last_download == (std::numeric_limits<std::int16_t>::min)() ? -1
: clamped_subtract_u16(m_ses.session_time(), m_last_download);
st->time_since_upload = int(total_seconds(aux::time_now()
- m_last_upload));
st->time_since_download = int(total_seconds(aux::time_now()
- m_last_download));
#endif
st->finished_duration = seconds{finished_time()};
st->active_duration = seconds{active_time()};
st->seeding_duration = seconds{seeding_time()};
st->finished_duration = finished_time();
st->active_duration = active_time();
st->seeding_duration = seeding_time();
st->last_upload = m_ses.session_start_time() + seconds(m_last_upload);
st->last_download = m_ses.session_start_time() + seconds(m_last_download);
st->last_upload = m_last_upload;
st->last_download = m_last_download;
st->storage_mode = static_cast<storage_mode_t>(m_storage_mode);