forked from premiere/premiere-libtorrent
remove the timestamps and file sizes from the resume data. This makes saving resume data alot cheaper, since it doesn't have to go via the disk thread. It also removes an old-standing API usage issue where there was easily a race condition introduced between saving resume data and pausing a torrent.
This commit is contained in:
parent
6b63016b05
commit
ae7058e119
|
@ -110,7 +110,7 @@ namespace libtorrent {
|
|||
#endif
|
||||
|
||||
bool pending() const;
|
||||
void get_all(std::vector<alert*>& alerts, int& num_resume);
|
||||
void get_all(std::vector<alert*>& alerts);
|
||||
|
||||
template <class T>
|
||||
bool should_post() const
|
||||
|
@ -147,8 +147,6 @@ namespace libtorrent {
|
|||
void set_dispatch_function(boost::function<void(std::auto_ptr<alert>)> const&);
|
||||
#endif
|
||||
|
||||
int num_queued_resume() const;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
void add_extension(boost::shared_ptr<plugin> ext);
|
||||
#endif
|
||||
|
@ -179,9 +177,6 @@ namespace libtorrent {
|
|||
// posted to the queue
|
||||
boost::function<void()> m_notify;
|
||||
|
||||
// the number of resume data alerts in the alert queue
|
||||
int m_num_queued_resume;
|
||||
|
||||
// this is either 0 or 1, it indicates which m_alerts and m_allocations
|
||||
// the alert_manager is allowed to use right now. This is swapped when
|
||||
// the client calls get_all(), at which point all of the alert objects
|
||||
|
|
|
@ -781,16 +781,6 @@ namespace libtorrent
|
|||
|
||||
std::map<std::string, boost::shared_ptr<torrent> > m_uuids;
|
||||
|
||||
// when saving resume data for many torrents, torrents are
|
||||
// queued up in this list in order to not have too many of them
|
||||
// outstanding at any given time, since the resume data may use
|
||||
// a lot of memory.
|
||||
std::list<boost::shared_ptr<torrent> > m_save_resume_queue;
|
||||
|
||||
// the number of save resume data disk jobs that are currently
|
||||
// outstanding
|
||||
int m_num_save_resume;
|
||||
|
||||
// peer connections are put here when disconnected to avoid
|
||||
// race conditions with the disk thread. It's important that
|
||||
// peer connections are destructed from the network thread,
|
||||
|
@ -1162,12 +1152,6 @@ namespace libtorrent
|
|||
std::list<boost::shared_ptr<tracker_logger> > m_tracker_loggers;
|
||||
#endif
|
||||
|
||||
// TODO: 2 the throttling of saving resume data could probably be
|
||||
// factored out into a separate class
|
||||
virtual void queue_async_resume_data(boost::shared_ptr<torrent> const& t) TORRENT_OVERRIDE;
|
||||
virtual void done_async_resume() TORRENT_OVERRIDE;
|
||||
void async_resume_dispatched();
|
||||
|
||||
// state for keeping track of external IPs
|
||||
external_ip m_external_ip;
|
||||
|
||||
|
|
|
@ -166,8 +166,6 @@ namespace libtorrent { namespace aux
|
|||
virtual bool has_connection(peer_connection* p) const = 0;
|
||||
virtual void insert_peer(boost::shared_ptr<peer_connection> const& c) = 0;
|
||||
|
||||
virtual void queue_async_resume_data(boost::shared_ptr<torrent> const& t) = 0;
|
||||
virtual void done_async_resume() = 0;
|
||||
virtual void evict_torrent(torrent* t) = 0;
|
||||
|
||||
virtual void remove_torrent(torrent_handle const& h, int options = 0) = 0;
|
||||
|
|
|
@ -86,8 +86,6 @@ namespace libtorrent
|
|||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_delete_files(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_save_resume_data(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_set_file_priority(piece_manager* storage
|
||||
, std::vector<boost::uint8_t> const& prio
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
|
|
|
@ -89,7 +89,6 @@ namespace libtorrent
|
|||
, release_files
|
||||
, delete_files
|
||||
, check_fastresume
|
||||
, save_resume_data
|
||||
, rename_file
|
||||
, stop_torrent
|
||||
, cache_piece
|
||||
|
@ -151,8 +150,6 @@ namespace libtorrent
|
|||
// for other jobs, it may point to other job-specific types
|
||||
// for move_storage and rename_file this is a string allocated
|
||||
// with malloc()
|
||||
// an entry* for save_resume_data
|
||||
// for aiocb_complete this points to the aiocb that completed
|
||||
// for get_cache_info this points to a cache_status object which
|
||||
// is filled in
|
||||
union
|
||||
|
|
|
@ -317,8 +317,6 @@ namespace libtorrent
|
|||
, bdecode_node const* resume_data
|
||||
, std::vector<std::string>& links
|
||||
, boost::function<void(disk_io_job const*)> const& handler);
|
||||
void async_save_resume_data(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler);
|
||||
void async_rename_file(piece_manager* storage, int index, std::string const& name
|
||||
, boost::function<void(disk_io_job const*)> const& handler);
|
||||
void async_stop_torrent(piece_manager* storage
|
||||
|
@ -414,7 +412,6 @@ namespace libtorrent
|
|||
int do_release_files(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_delete_files(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_check_fastresume(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_save_resume_data(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_rename_file(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_stop_torrent(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_read_and_hash(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
|
|
|
@ -437,6 +437,7 @@ namespace libtorrent
|
|||
enable_outgoing_tcp,
|
||||
enable_incoming_tcp,
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// ``ignore_resume_timestamps`` determines if the storage, when
|
||||
// loading resume data files, should verify that the file modification
|
||||
// time with the timestamps in the resume data. This defaults to
|
||||
|
@ -447,6 +448,10 @@ namespace libtorrent
|
|||
// redownload potentially missed pieces than to go through the whole
|
||||
// storage to look for them.
|
||||
ignore_resume_timestamps,
|
||||
#else
|
||||
// hidden
|
||||
deprecated8,
|
||||
#endif
|
||||
|
||||
// ``no_recheck_incomplete_resume`` determines if the storage should
|
||||
// check the whole files when resume data is incomplete or missing or
|
||||
|
|
|
@ -113,7 +113,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
// virtual bool verify_resume_data(bdecode_node const& rd
|
||||
// , std::vector<std::string> const* links
|
||||
// , storage_error& error) { return false; }
|
||||
// virtual bool write_resume_data(entry& rd) const { return false; }
|
||||
// virtual boost::int64_t physical_offset(int piece, int offset)
|
||||
// { return piece * m_files.piece_length() + offset; };
|
||||
// virtual sha1_hash hash_for_slot(int piece, partial_hash& ph, int piece_size)
|
||||
|
@ -314,16 +313,6 @@ namespace libtorrent
|
|||
, std::vector<std::string> const* links
|
||||
, storage_error& ec) = 0;
|
||||
|
||||
// This function should fill in resume data, the current state of the
|
||||
// storage, in ``rd``. The default storage adds file timestamps and
|
||||
// sizes.
|
||||
//
|
||||
// Returning ``true`` indicates an error occurred.
|
||||
//
|
||||
// If an error occurs, ``storage_error`` should be set to reflect it.
|
||||
//
|
||||
virtual void write_resume_data(entry& rd, storage_error& ec) const = 0;
|
||||
|
||||
// This function should release all the file handles that it keeps open
|
||||
// to files belonging to this storage. The default implementation just
|
||||
// calls file_pool::release_files().
|
||||
|
@ -433,7 +422,6 @@ namespace libtorrent
|
|||
virtual bool verify_resume_data(bdecode_node const& rd
|
||||
, std::vector<std::string> const* links
|
||||
, storage_error& error) TORRENT_OVERRIDE;
|
||||
virtual void write_resume_data(entry& rd, storage_error& ec) const TORRENT_OVERRIDE;
|
||||
virtual bool tick() TORRENT_OVERRIDE;
|
||||
|
||||
int readv(file::iovec_t const* bufs, int num_bufs
|
||||
|
@ -518,7 +506,6 @@ namespace libtorrent
|
|||
virtual bool verify_resume_data(bdecode_node const&
|
||||
, std::vector<std::string> const*
|
||||
, storage_error&) TORRENT_OVERRIDE { return false; }
|
||||
virtual void write_resume_data(entry&, storage_error&) const TORRENT_OVERRIDE {}
|
||||
};
|
||||
|
||||
// this storage implementation always reads zeroes, and always discards
|
||||
|
@ -541,7 +528,6 @@ namespace libtorrent
|
|||
, std::vector<std::string> const* /* links */
|
||||
, storage_error&) TORRENT_OVERRIDE
|
||||
{ return false; }
|
||||
virtual void write_resume_data(entry&, storage_error&) const TORRENT_OVERRIDE {}
|
||||
virtual void release_files(storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void rename_file(int /* index */
|
||||
, std::string const& /* new_filenamem */, storage_error&) TORRENT_OVERRIDE {}
|
||||
|
@ -661,8 +647,6 @@ namespace libtorrent
|
|||
|
||||
storage_interface* get_storage_impl() { return m_storage.get(); }
|
||||
|
||||
void write_resume_data(entry& rd, storage_error& ec) const;
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
void assert_torrent_refcount() const;
|
||||
#endif
|
||||
|
|
|
@ -480,7 +480,6 @@ namespace libtorrent
|
|||
bool is_torrent_paused() const { return !m_allow_peers || m_graceful_pause_mode; }
|
||||
void force_recheck();
|
||||
void save_resume_data(int flags);
|
||||
bool do_async_save_resume_data();
|
||||
|
||||
bool need_save_resume_data() const
|
||||
{
|
||||
|
@ -1138,7 +1137,6 @@ namespace libtorrent
|
|||
void on_files_deleted(disk_io_job const* j);
|
||||
void on_torrent_paused(disk_io_job const* j);
|
||||
void on_storage_moved(disk_io_job const* j);
|
||||
void on_save_resume_data(disk_io_job const* j);
|
||||
void on_file_renamed(disk_io_job const* j);
|
||||
void on_cache_flushed(disk_io_job const* j);
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@ namespace libtorrent
|
|||
void rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
TORRENT_ASSERT(is_loaded());
|
||||
if (m_files.file_name(index) == new_filename) return;
|
||||
copy_on_write();
|
||||
m_files.rename_file(index, new_filename);
|
||||
}
|
||||
|
|
|
@ -44,18 +44,11 @@ namespace libtorrent
|
|||
alert_manager::alert_manager(int queue_limit, boost::uint32_t alert_mask)
|
||||
: m_alert_mask(alert_mask)
|
||||
, m_queue_size_limit(queue_limit)
|
||||
, m_num_queued_resume(0)
|
||||
, m_generation(0)
|
||||
{}
|
||||
|
||||
alert_manager::~alert_manager() {}
|
||||
|
||||
int alert_manager::num_queued_resume() const
|
||||
{
|
||||
mutex::scoped_lock lock(m_mutex);
|
||||
return m_num_queued_resume;
|
||||
}
|
||||
|
||||
alert* alert_manager::wait_for_alert(time_duration max_wait)
|
||||
{
|
||||
mutex::scoped_lock lock(m_mutex);
|
||||
|
@ -73,10 +66,6 @@ namespace libtorrent
|
|||
|
||||
void alert_manager::maybe_notify(alert* a, mutex::scoped_lock& lock)
|
||||
{
|
||||
if (a->type() == save_resume_data_failed_alert::alert_type
|
||||
|| a->type() == save_resume_data_alert::alert_type)
|
||||
++m_num_queued_resume;
|
||||
|
||||
if (m_alerts[m_generation].size() == 1)
|
||||
{
|
||||
lock.unlock();
|
||||
|
@ -102,6 +91,8 @@ namespace libtorrent
|
|||
{
|
||||
(*i)->on_alert(a);
|
||||
}
|
||||
#else
|
||||
TORRENT_UNUSED(a);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -168,17 +159,14 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
void alert_manager::get_all(std::vector<alert*>& alerts, int& num_resume)
|
||||
void alert_manager::get_all(std::vector<alert*>& alerts)
|
||||
{
|
||||
mutex::scoped_lock lock(m_mutex);
|
||||
TORRENT_ASSERT(m_num_queued_resume <= m_alerts[m_generation].size());
|
||||
|
||||
alerts.clear();
|
||||
if (m_alerts[m_generation].empty()) return;
|
||||
|
||||
m_alerts[m_generation].get_pointers(alerts);
|
||||
num_resume = m_num_queued_resume;
|
||||
m_num_queued_resume = 0;
|
||||
|
||||
// swap buffers
|
||||
m_generation = (m_generation + 1) & 1;
|
||||
|
|
|
@ -214,7 +214,6 @@ const char* const job_action_name[] =
|
|||
"release_files",
|
||||
"delete_files",
|
||||
"check_fastresume",
|
||||
"save_resume_data",
|
||||
"rename_file",
|
||||
"stop_torrent",
|
||||
"cache_piece",
|
||||
|
|
|
@ -52,7 +52,6 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_ref.storage == 0 || m_ref.block >= 0);
|
||||
TORRENT_ASSERT(m_ref.storage == 0 || m_ref.piece < static_cast<piece_manager*>(m_ref.storage)->files()->num_pieces());
|
||||
TORRENT_ASSERT(m_ref.storage == 0 || m_ref.block <= static_cast<piece_manager*>(m_ref.storage)->files()->piece_length() / 0x4000);
|
||||
TORRENT_ASSERT(j.action != disk_io_job::save_resume_data);
|
||||
TORRENT_ASSERT(j.action != disk_io_job::rename_file);
|
||||
TORRENT_ASSERT(j.action != disk_io_job::move_storage);
|
||||
}
|
||||
|
@ -69,7 +68,6 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_ref.block >= 0);
|
||||
TORRENT_ASSERT(m_ref.piece < static_cast<piece_manager*>(m_ref.storage)->files()->num_pieces());
|
||||
TORRENT_ASSERT(m_ref.block <= static_cast<piece_manager*>(m_ref.storage)->files()->piece_length() / 0x4000);
|
||||
TORRENT_ASSERT(j.action != disk_io_job::save_resume_data);
|
||||
TORRENT_ASSERT(j.action != disk_io_job::rename_file);
|
||||
TORRENT_ASSERT(j.action != disk_io_job::move_storage);
|
||||
}
|
||||
|
|
|
@ -62,8 +62,6 @@ namespace libtorrent
|
|||
{
|
||||
if (action == rename_file || action == move_storage)
|
||||
free(buffer.string);
|
||||
else if (action == save_resume_data)
|
||||
delete static_cast<entry*>(buffer.resume_data);
|
||||
}
|
||||
|
||||
bool disk_io_job::completed(cached_piece_entry const* pe, int block_size)
|
||||
|
|
|
@ -1038,7 +1038,6 @@ namespace libtorrent
|
|||
&disk_io_thread::do_release_files,
|
||||
&disk_io_thread::do_delete_files,
|
||||
&disk_io_thread::do_check_fastresume,
|
||||
&disk_io_thread::do_save_resume_data,
|
||||
&disk_io_thread::do_rename_file,
|
||||
&disk_io_thread::do_stop_torrent,
|
||||
&disk_io_thread::do_cache_piece,
|
||||
|
@ -1904,23 +1903,6 @@ namespace libtorrent
|
|||
add_fence_job(storage, j);
|
||||
}
|
||||
|
||||
void disk_io_thread::async_save_resume_data(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler)
|
||||
{
|
||||
#ifdef TORRENT_DEBUG
|
||||
// the caller must increment the torrent refcount before
|
||||
// issuing an async disk request
|
||||
storage->assert_torrent_refcount();
|
||||
#endif
|
||||
|
||||
disk_io_job* j = allocate_job(disk_io_job::save_resume_data);
|
||||
j->storage = storage->shared_from_this();
|
||||
j->buffer.resume_data = NULL;
|
||||
j->callback = handler;
|
||||
|
||||
add_fence_job(storage, j);
|
||||
}
|
||||
|
||||
void disk_io_thread::async_rename_file(piece_manager* storage, int index, std::string const& name
|
||||
, boost::function<void(disk_io_job const*)> const& handler)
|
||||
{
|
||||
|
@ -2601,22 +2583,6 @@ namespace libtorrent
|
|||
return j->storage->check_fastresume(*rd, links.get(), j->error);
|
||||
}
|
||||
|
||||
int disk_io_thread::do_save_resume_data(disk_io_job* j, jobqueue_t& completed_jobs)
|
||||
{
|
||||
// if this assert fails, something's wrong with the fence logic
|
||||
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
|
||||
|
||||
mutex::scoped_lock l(m_cache_mutex);
|
||||
flush_cache(j->storage.get(), flush_write_cache, completed_jobs, l);
|
||||
l.unlock();
|
||||
|
||||
entry* resume_data = new entry(entry::dictionary_t);
|
||||
j->storage->get_storage_impl()->write_resume_data(*resume_data, j->error);
|
||||
TORRENT_ASSERT(j->buffer.resume_data == 0);
|
||||
j->buffer.resume_data = resume_data;
|
||||
return j->error ? -1 : 0;
|
||||
}
|
||||
|
||||
int disk_io_thread::do_rename_file(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
|
||||
{
|
||||
// if this assert fails, something's wrong with the fence logic
|
||||
|
|
|
@ -379,7 +379,6 @@ namespace aux {
|
|||
, *this
|
||||
#endif
|
||||
)
|
||||
, m_num_save_resume(0)
|
||||
, m_work(io_service::work(m_io_service))
|
||||
, m_max_queue_pos(-1)
|
||||
, m_key(0)
|
||||
|
@ -642,58 +641,6 @@ namespace aux {
|
|||
m_host_resolver.async_resolve(host, flags, h);
|
||||
}
|
||||
|
||||
void session_impl::queue_async_resume_data(boost::shared_ptr<torrent> const& t)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
||||
|
||||
if (m_num_save_resume + m_alerts.num_queued_resume() >= loaded_limit
|
||||
&& m_user_load_torrent
|
||||
&& loaded_limit > 0)
|
||||
{
|
||||
TORRENT_ASSERT(t);
|
||||
// do loaded torrents first, otherwise they'll just be
|
||||
// evicted and have to be loaded again
|
||||
if (t->is_loaded())
|
||||
m_save_resume_queue.push_front(t);
|
||||
else
|
||||
m_save_resume_queue.push_back(t);
|
||||
return;
|
||||
}
|
||||
|
||||
if (t->do_async_save_resume_data())
|
||||
++m_num_save_resume;
|
||||
}
|
||||
|
||||
// this is called whenever a save_resume_data comes back
|
||||
// from the disk thread
|
||||
void session_impl::done_async_resume()
|
||||
{
|
||||
TORRENT_ASSERT(m_num_save_resume > 0);
|
||||
--m_num_save_resume;
|
||||
}
|
||||
|
||||
// this is called when one or all save resume alerts are
|
||||
// popped off the alert queue
|
||||
void session_impl::async_resume_dispatched()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
int num_queued_resume = m_alerts.num_queued_resume();
|
||||
|
||||
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
||||
while (!m_save_resume_queue.empty()
|
||||
&& (m_num_save_resume + num_queued_resume < loaded_limit
|
||||
|| loaded_limit == 0))
|
||||
{
|
||||
boost::shared_ptr<torrent> t = m_save_resume_queue.front();
|
||||
m_save_resume_queue.erase(m_save_resume_queue.begin());
|
||||
if (t->do_async_save_resume_data())
|
||||
++m_num_save_resume;
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::save_state(entry* eptr, boost::uint32_t flags) const
|
||||
{
|
||||
TORRENT_ASSERT(is_single_thread());
|
||||
|
@ -6452,15 +6399,7 @@ retry:
|
|||
|
||||
void session_impl::pop_alerts(std::vector<alert*>* alerts)
|
||||
{
|
||||
int num_resume = 0;
|
||||
m_alerts.get_all(*alerts, num_resume);
|
||||
if (num_resume > 0)
|
||||
{
|
||||
// we can only issue more resume data jobs from
|
||||
// the network thread
|
||||
m_io_service.post(boost::bind(&session_impl::async_resume_dispatched
|
||||
, this));
|
||||
}
|
||||
m_alerts.get_all(*alerts);
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
|
@ -6892,11 +6831,6 @@ retry:
|
|||
{
|
||||
TORRENT_ASSERT(is_single_thread());
|
||||
|
||||
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
||||
TORRENT_ASSERT(m_num_save_resume <= loaded_limit);
|
||||
// if (m_num_save_resume < loaded_limit)
|
||||
// TORRENT_ASSERT(m_save_resume_queue.empty());
|
||||
|
||||
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
|
||||
|
||||
if (m_settings.get_int(settings_pack::unchoke_slots_limit) < 0
|
||||
|
|
|
@ -38,6 +38,9 @@ namespace libtorrent
|
|||
stat_cache::stat_cache() {}
|
||||
stat_cache::~stat_cache() {}
|
||||
|
||||
// TODO: 4 improve this interface by fall back to the actual stat() call internally. Don't
|
||||
// expose low-level functions to query the cache and set cache state. Also, we should
|
||||
// probably cache the error_code too
|
||||
void stat_cache::set_cache(int i, boost::int64_t size, time_t time)
|
||||
{
|
||||
TORRENT_ASSERT(i >= 0);
|
||||
|
@ -76,6 +79,7 @@ namespace libtorrent
|
|||
return m_stat_cache[i].file_size;
|
||||
}
|
||||
|
||||
// TODO: 4 file_time can probably be removed from the cache now
|
||||
time_t stat_cache::get_filetime(int i) const
|
||||
{
|
||||
if (i >= int(m_stat_cache.size())) return not_in_cache;
|
||||
|
|
302
src/storage.cpp
302
src/storage.cpp
|
@ -831,244 +831,12 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
void default_storage::write_resume_data(entry& rd, storage_error& ec) const
|
||||
{
|
||||
TORRENT_ASSERT(rd.type() == entry::dictionary_t);
|
||||
|
||||
entry::list_type& fl = rd["file sizes"].list();
|
||||
|
||||
if (m_part_file)
|
||||
{
|
||||
error_code ignore;
|
||||
const_cast<part_file&>(*m_part_file).flush_metadata(ignore);
|
||||
}
|
||||
|
||||
file_storage const& fs = files();
|
||||
for (int i = 0; i < fs.num_files(); ++i)
|
||||
{
|
||||
boost::int64_t file_size = 0;
|
||||
time_t file_time = 0;
|
||||
boost::int64_t cache_state = m_stat_cache.get_filesize(i);
|
||||
if (cache_state != stat_cache::not_in_cache)
|
||||
{
|
||||
if (cache_state >= 0)
|
||||
{
|
||||
file_size = cache_state;
|
||||
file_time = m_stat_cache.get_filetime(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file_status s;
|
||||
error_code error;
|
||||
stat_file(fs.file_path(i, m_save_path), &s, error);
|
||||
if (!error)
|
||||
{
|
||||
file_size = s.file_size;
|
||||
file_time = s.mtime;
|
||||
}
|
||||
else if (error == error_code(boost::system::errc::no_such_file_or_directory
|
||||
, generic_category()))
|
||||
{
|
||||
m_stat_cache.set_noexist(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.ec = error;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
m_stat_cache.set_error(i);
|
||||
}
|
||||
}
|
||||
|
||||
fl.push_back(entry(entry::list_t));
|
||||
entry::list_type& p = fl.back().list();
|
||||
p.push_back(entry(file_size));
|
||||
p.push_back(entry(file_time));
|
||||
}
|
||||
}
|
||||
|
||||
bool default_storage::verify_resume_data(bdecode_node const& rd
|
||||
, std::vector<std::string> const* links
|
||||
, storage_error& ec)
|
||||
{
|
||||
// TODO: make this more generic to not just work if files have been
|
||||
// renamed, but also if they have been merged into a single file for instance
|
||||
// maybe use the same format as .torrent files and reuse some code from torrent_info
|
||||
bdecode_node mapped_files = rd.dict_find_list("mapped_files");
|
||||
if (mapped_files && mapped_files.list_size() == m_files.num_files())
|
||||
{
|
||||
m_mapped_files.reset(new file_storage(m_files));
|
||||
for (int i = 0; i < m_files.num_files(); ++i)
|
||||
{
|
||||
std::string new_filename = mapped_files.list_string_value_at(i);
|
||||
if (new_filename.empty()) continue;
|
||||
m_mapped_files->rename_file(i, new_filename);
|
||||
}
|
||||
}
|
||||
|
||||
bdecode_node file_priority = rd.dict_find_list("file_priority");
|
||||
if (file_priority && file_priority.list_size()
|
||||
== files().num_files())
|
||||
{
|
||||
m_file_priority.resize(file_priority.list_size());
|
||||
for (int i = 0; i < file_priority.list_size(); ++i)
|
||||
m_file_priority[i] = boost::uint8_t(file_priority.list_int_value_at(i, 1));
|
||||
}
|
||||
|
||||
bdecode_node file_sizes_ent = rd.dict_find_list("file sizes");
|
||||
if (file_sizes_ent == 0)
|
||||
{
|
||||
ec.ec = errors::missing_file_sizes;
|
||||
ec.file = -1;
|
||||
ec.operation = storage_error::check_resume;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_sizes_ent.list_size() == 0)
|
||||
{
|
||||
ec.ec = errors::no_files_in_resume_data;
|
||||
return false;
|
||||
}
|
||||
|
||||
file_storage const& fs = files();
|
||||
if (file_sizes_ent.list_size() != fs.num_files())
|
||||
{
|
||||
ec.ec = errors::mismatching_number_of_files;
|
||||
ec.file = -1;
|
||||
ec.operation = storage_error::check_resume;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool seed = false;
|
||||
bdecode_node slots = rd.dict_find_list("slots");
|
||||
if (slots)
|
||||
{
|
||||
if (int(slots.list_size()) == m_files.num_pieces())
|
||||
{
|
||||
seed = true;
|
||||
for (int i = 0; i < slots.list_size(); ++i)
|
||||
{
|
||||
if (slots.list_int_value_at(i, -1) >= 0) continue;
|
||||
seed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bdecode_node pieces = rd.dict_find_string("pieces"))
|
||||
{
|
||||
if (int(pieces.string_length()) == m_files.num_pieces())
|
||||
{
|
||||
seed = true;
|
||||
char const* p = pieces.string_ptr();
|
||||
for (int i = 0; i < pieces.string_length(); ++i)
|
||||
{
|
||||
if ((p[i] & 1) == 1) continue;
|
||||
seed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.ec = errors::missing_pieces;
|
||||
ec.file = -1;
|
||||
ec.operation = storage_error::check_resume;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < file_sizes_ent.list_size(); ++i)
|
||||
{
|
||||
if (fs.pad_file_at(i)) continue;
|
||||
bdecode_node e = file_sizes_ent.list_at(i);
|
||||
if (e.type() != bdecode_node::list_t
|
||||
|| e.list_size() < 2
|
||||
|| e.list_at(0).type() != bdecode_node::int_t
|
||||
|| e.list_at(1).type() != bdecode_node::int_t)
|
||||
{
|
||||
ec.ec = errors::missing_file_sizes;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::check_resume;
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::int64_t expected_size = e.list_int_value_at(0);
|
||||
time_t expected_time = e.list_int_value_at(1);
|
||||
|
||||
// if we're a seed, the expected size should match
|
||||
// the actual full size according to the torrent
|
||||
if (seed && expected_size < fs.file_size(i))
|
||||
{
|
||||
ec.ec = errors::mismatching_file_size;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::check_resume;
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::int64_t file_size = m_stat_cache.get_filesize(i);
|
||||
time_t file_time;
|
||||
if (file_size >= 0)
|
||||
{
|
||||
file_time = m_stat_cache.get_filetime(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
file_status s;
|
||||
error_code error;
|
||||
std::string file_path = fs.file_path(i, m_save_path);
|
||||
stat_file(file_path, &s, error);
|
||||
if (error)
|
||||
{
|
||||
if (error != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
m_stat_cache.set_error(i);
|
||||
ec.ec = error;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
return false;
|
||||
}
|
||||
m_stat_cache.set_noexist(i);
|
||||
if (expected_size != 0)
|
||||
{
|
||||
ec.ec = errors::mismatching_file_size;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::none;
|
||||
return false;
|
||||
}
|
||||
file_size = 0;
|
||||
file_time = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
file_size = s.file_size;
|
||||
file_time = s.mtime;
|
||||
}
|
||||
}
|
||||
|
||||
if (expected_size > file_size)
|
||||
{
|
||||
ec.ec = errors::mismatching_file_size;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::none;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings().get_bool(settings_pack::ignore_resume_timestamps)) continue;
|
||||
|
||||
// allow some slack, because of FAT volumes
|
||||
if (expected_time != 0 &&
|
||||
(file_time > expected_time + 5 * 60 || file_time < expected_time - 5))
|
||||
{
|
||||
ec.ec = errors::mismatching_file_timestamp;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 2 we probably need to do this unconditionally in this function.
|
||||
// Even if the resume data file appears stale, we need to create these
|
||||
// hard links, right?
|
||||
#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
|
||||
if (links)
|
||||
{
|
||||
|
@ -1104,6 +872,67 @@ namespace libtorrent
|
|||
}
|
||||
#endif // TORRENT_DISABLE_MUTABLE_TORRENTS
|
||||
|
||||
if (rd && rd.type() == bdecode_node::dict_t)
|
||||
{
|
||||
bdecode_node pieces = rd.dict_find_string("pieces");
|
||||
if (pieces && pieces.type() == bdecode_node::string_t
|
||||
&& int(pieces.string_length()) == fs.num_pieces())
|
||||
{
|
||||
char const* pieces_str = pieces.string_ptr();
|
||||
// parse have bitmask. Verify that the files we expect to have
|
||||
// actually do exist
|
||||
for (int i = 0; i < fs.num_pieces(); ++i)
|
||||
{
|
||||
if ((pieces_str[i] & 1) == 0) continue;
|
||||
|
||||
std::vector<file_slice> f = fs.map_block(i, 0, 1);
|
||||
TORRENT_ASSERT(!f.empty());
|
||||
|
||||
const int file_index = f[0].file_index;
|
||||
boost::int64_t size = m_stat_cache.get_filesize(f[0].file_index);
|
||||
|
||||
if (size == stat_cache::not_in_cache)
|
||||
{
|
||||
file_status s;
|
||||
error_code error;
|
||||
std::string file_path = fs.file_path(file_index, m_save_path);
|
||||
stat_file(file_path, &s, error);
|
||||
size = s.file_size;
|
||||
if (error)
|
||||
{
|
||||
if (error != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
m_stat_cache.set_error(i);
|
||||
ec.ec = error;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
return false;
|
||||
}
|
||||
m_stat_cache.set_noexist(i);
|
||||
ec.ec = errors::mismatching_file_size;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (size < 0)
|
||||
{
|
||||
ec.ec = errors::mismatching_file_size;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::check_resume;
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, this file existed, good. Now, skip all remaining pieces in
|
||||
// this file. We're just sanity-checking whether the files exist
|
||||
// or not.
|
||||
peer_request pr = fs.map_file(file_index, 0
|
||||
, fs.file_size(file_index) + 1);
|
||||
i = (std::max)(i + 1, pr.piece);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1597,12 +1426,6 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
// used in torrent_handle.cpp
|
||||
void piece_manager::write_resume_data(entry& rd, storage_error& ec) const
|
||||
{
|
||||
m_storage->write_resume_data(rd, ec);
|
||||
}
|
||||
|
||||
int piece_manager::check_no_fastresume(storage_error& ec)
|
||||
{
|
||||
bool has_files = false;
|
||||
|
@ -1631,13 +1454,14 @@ namespace libtorrent
|
|||
int piece_manager::check_init_storage(storage_error& ec)
|
||||
{
|
||||
storage_error se;
|
||||
// initialize may clear the error we pass in and it's important to
|
||||
// preserve the error code in ec, even when initialize() is successful
|
||||
m_storage->initialize(se);
|
||||
if (se)
|
||||
{
|
||||
ec = se;
|
||||
return fatal_disk_error;
|
||||
}
|
||||
|
||||
return no_error;
|
||||
}
|
||||
|
||||
|
|
104
src/torrent.cpp
104
src/torrent.cpp
|
@ -5036,35 +5036,6 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::on_save_resume_data(disk_io_job const* j)
|
||||
{
|
||||
TORRENT_ASSERT(is_single_thread());
|
||||
torrent_ref_holder h(this, "save_resume");
|
||||
dec_refcount("save_resume");
|
||||
m_ses.done_async_resume();
|
||||
|
||||
if (!j->buffer.resume_data)
|
||||
{
|
||||
alerts().emplace_alert<save_resume_data_failed_alert>(get_handle(), j->error.ec);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!need_loaded())
|
||||
{
|
||||
alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
|
||||
, m_error);
|
||||
return;
|
||||
}
|
||||
|
||||
m_need_save_resume_data = false;
|
||||
m_last_saved_resume = m_ses.session_time();
|
||||
write_resume_data(*j->buffer.resume_data);
|
||||
alerts().emplace_alert<save_resume_data_alert>(
|
||||
boost::shared_ptr<entry>(j->buffer.resume_data), get_handle());
|
||||
const_cast<disk_io_job*>(j)->buffer.resume_data = 0;
|
||||
state_updated();
|
||||
}
|
||||
|
||||
void torrent::on_file_renamed(disk_io_job const* j)
|
||||
{
|
||||
TORRENT_ASSERT(is_single_thread());
|
||||
|
@ -5521,10 +5492,6 @@ namespace libtorrent
|
|||
// this call is only valid on torrents with metadata
|
||||
if (!valid_metadata() || is_seed()) return;
|
||||
|
||||
// the vector need to have exactly one element for every file
|
||||
// in the torrent
|
||||
TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
|
||||
|
||||
int limit = int(files.size());
|
||||
if (valid_metadata() && limit > m_torrent_file->num_files())
|
||||
limit = m_torrent_file->num_files();
|
||||
|
@ -5545,7 +5512,7 @@ namespace libtorrent
|
|||
m_file_priority[i] = 0;
|
||||
}
|
||||
|
||||
// storage may be NULL during shutdown
|
||||
// storage may be NULL during construction and shutdown
|
||||
if (m_torrent_file->num_pieces() > 0 && m_storage)
|
||||
{
|
||||
inc_refcount("file_priority");
|
||||
|
@ -6916,9 +6883,6 @@ namespace libtorrent
|
|||
m_ses.insert_uuid_torrent(m_uuid.empty() ? m_url : m_uuid, me);
|
||||
}
|
||||
|
||||
// TODO: make this more generic to not just work if files have been
|
||||
// renamed, but also if they have been merged into a single file for instance
|
||||
// maybe use the same format as .torrent files and reuse some code from torrent_info
|
||||
// The mapped_files needs to be read both in the network thread
|
||||
// and in the disk thread, since they both have their own mapped files structures
|
||||
// which are kept in sync
|
||||
|
@ -6947,28 +6911,15 @@ namespace libtorrent
|
|||
{
|
||||
const int num_files = (std::min)(file_priority.list_size()
|
||||
, m_torrent_file->num_files());
|
||||
m_file_priority.resize(num_files, 4);
|
||||
std::vector<int> file_prio(num_files);
|
||||
for (int i = 0; i < num_files; ++i)
|
||||
{
|
||||
m_file_priority[i] = file_priority.list_int_value_at(i, 1);
|
||||
file_prio[i] = file_priority.list_int_value_at(i, 1);
|
||||
// this is suspicious, leave seed mode
|
||||
if (m_file_priority[i] == 0) m_seed_mode = false;
|
||||
}
|
||||
// unallocated slots are assumed to be priority 1, so cut off any
|
||||
// trailing ones
|
||||
int end_range = num_files - 1;
|
||||
for (; end_range >= 0; --end_range) if (m_file_priority[end_range] != 1) break;
|
||||
m_file_priority.resize(end_range + 1, 4);
|
||||
|
||||
// initialize pad files to priority 0
|
||||
file_storage const& fs = m_torrent_file->files();
|
||||
for (int i = 0; i < (std::min)(fs.num_files(), end_range + 1); ++i)
|
||||
{
|
||||
if (!fs.pad_file_at(i)) continue;
|
||||
m_file_priority[i] = 0;
|
||||
if (file_prio[i] == 0) m_seed_mode = false;
|
||||
}
|
||||
|
||||
update_piece_priorities();
|
||||
prioritize_files(file_prio);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7275,9 +7226,6 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
// write renamed files
|
||||
// TODO: 0 make this more generic to not just work if files have been
|
||||
// renamed, but also if they have been merged into a single file for instance.
|
||||
// using file_base
|
||||
if (&m_torrent_file->files() != &m_torrent_file->orig_files()
|
||||
&& m_torrent_file->files().num_files() == m_torrent_file->orig_files().num_files())
|
||||
{
|
||||
|
@ -8766,7 +8714,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_torrent_file->num_files());
|
||||
|
||||
// stoage may be NULL during shutdown
|
||||
// storage may be NULL during shutdown
|
||||
if (!m_storage.get())
|
||||
{
|
||||
if (alerts().should_post<file_rename_failed_alert>())
|
||||
|
@ -9558,16 +9506,13 @@ namespace libtorrent
|
|||
m_save_resume_flags = boost::uint8_t(flags);
|
||||
state_updated();
|
||||
|
||||
if (m_state == torrent_status::checking_files
|
||||
|| m_state == torrent_status::checking_resume_data)
|
||||
{
|
||||
if (!need_loaded())
|
||||
{
|
||||
alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
|
||||
, m_error);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// storage may be NULL during shutdown
|
||||
if (!m_storage)
|
||||
{
|
||||
|
@ -9576,40 +9521,15 @@ namespace libtorrent
|
|||
, boost::asio::error::operation_aborted);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
if ((flags & torrent_handle::flush_disk_cache) && m_storage.get())
|
||||
m_ses.disk_thread().async_release_files(m_storage.get());
|
||||
|
||||
state_updated();
|
||||
|
||||
boost::shared_ptr<entry> rd(new entry);
|
||||
write_resume_data(*rd);
|
||||
alerts().emplace_alert<save_resume_data_alert>(rd, get_handle());
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 3 this really needs to be moved to do_async_save_resume_data.
|
||||
// flags need to be passed on
|
||||
if ((flags & torrent_handle::flush_disk_cache) && m_storage.get())
|
||||
m_ses.disk_thread().async_release_files(m_storage.get());
|
||||
|
||||
m_ses.queue_async_resume_data(shared_from_this());
|
||||
}
|
||||
|
||||
bool torrent::do_async_save_resume_data()
|
||||
{
|
||||
if (!need_loaded())
|
||||
{
|
||||
alerts().emplace_alert<save_resume_data_failed_alert>(get_handle(), m_error);
|
||||
return false;
|
||||
}
|
||||
// storage may be NULL during shutdown
|
||||
if (!m_storage)
|
||||
{
|
||||
TORRENT_ASSERT(m_abort);
|
||||
alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
|
||||
, boost::asio::error::operation_aborted);
|
||||
return false;
|
||||
}
|
||||
inc_refcount("save_resume");
|
||||
m_ses.disk_thread().async_save_resume_data(m_storage.get()
|
||||
, boost::bind(&torrent::on_save_resume_data, shared_from_this(), _1));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool torrent::should_check_files() const
|
||||
|
|
|
@ -734,19 +734,6 @@ namespace libtorrent
|
|||
{
|
||||
entry ret(entry::dictionary_t);
|
||||
TORRENT_SYNC_CALL1(write_resume_data, boost::ref(ret));
|
||||
t = m_torrent.lock();
|
||||
if (t)
|
||||
{
|
||||
bool done = false;
|
||||
session_impl& ses = static_cast<session_impl&>(t->session());
|
||||
storage_error ec;
|
||||
ses.get_io_service().dispatch(boost::bind(&aux::fun_wrap, boost::ref(done), boost::ref(ses.cond)
|
||||
, boost::ref(ses.mut), boost::function<void(void)>(boost::bind(
|
||||
&piece_manager::write_resume_data, &t->storage(), boost::ref(ret), boost::ref(ec)))));
|
||||
t.reset();
|
||||
aux::torrent_wait(done, ses);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ TORRENT_TEST(limit)
|
|||
TEST_EQUAL(mgr.pending(), true);
|
||||
|
||||
std::vector<alert*> alerts;
|
||||
int num_resume;
|
||||
mgr.get_all(alerts, num_resume);
|
||||
mgr.get_all(alerts);
|
||||
|
||||
// even though we posted 600, the limit was 500
|
||||
TEST_EQUAL(alerts.size(), 500);
|
||||
|
@ -75,7 +74,7 @@ TORRENT_TEST(limit)
|
|||
|
||||
TEST_EQUAL(mgr.pending(), true);
|
||||
|
||||
mgr.get_all(alerts, num_resume);
|
||||
mgr.get_all(alerts);
|
||||
|
||||
// even though we posted 600, the limit was 200
|
||||
TEST_EQUAL(alerts.size(), 200);
|
||||
|
@ -96,8 +95,7 @@ TORRENT_TEST(priority_limit)
|
|||
mgr.emplace_alert<file_rename_failed_alert>(torrent_handle(), i, error_code());
|
||||
|
||||
std::vector<alert*> alerts;
|
||||
int num_resume;
|
||||
mgr.get_all(alerts, num_resume);
|
||||
mgr.get_all(alerts);
|
||||
|
||||
// even though we posted 400, the limit was 100 for half of them and
|
||||
// 200 for the other half, meaning we should have 200 alerts now
|
||||
|
@ -173,8 +171,7 @@ TORRENT_TEST(notify_function)
|
|||
// however, if we pop all the alerts and post new ones, there will be
|
||||
// and edge triggering the notify call
|
||||
std::vector<alert*> alerts;
|
||||
int num_resume;
|
||||
mgr.get_all(alerts, num_resume);
|
||||
mgr.get_all(alerts);
|
||||
|
||||
TEST_EQUAL(mgr.pending(), false);
|
||||
|
||||
|
@ -258,8 +255,7 @@ TORRENT_TEST(wait_for_alert)
|
|||
TEST_CHECK(a->type() == torrent_added_alert::alert_type);
|
||||
|
||||
std::vector<alert*> alerts;
|
||||
int num_resume = 0;
|
||||
mgr.get_all(alerts, num_resume);
|
||||
mgr.get_all(alerts);
|
||||
|
||||
start = clock_type::now();
|
||||
thread posting_thread(boost::bind(&post_torrent_added, &mgr));
|
||||
|
@ -274,40 +270,6 @@ TORRENT_TEST(wait_for_alert)
|
|||
posting_thread.join();
|
||||
}
|
||||
|
||||
TORRENT_TEST(queued_resume)
|
||||
{
|
||||
alert_manager mgr(100, 0xffffffff);
|
||||
|
||||
TEST_EQUAL(mgr.num_queued_resume(), 0);
|
||||
|
||||
for (int i = 0; i < 17; ++i)
|
||||
mgr.emplace_alert<torrent_added_alert>(torrent_handle());
|
||||
|
||||
TEST_EQUAL(mgr.num_queued_resume(), 0);
|
||||
|
||||
std::vector<alert*> alerts;
|
||||
int num_resume = 0;
|
||||
mgr.get_all(alerts, num_resume);
|
||||
TEST_EQUAL(num_resume, 0);
|
||||
TEST_EQUAL(alerts.size(), 17);
|
||||
|
||||
TEST_EQUAL(mgr.num_queued_resume(), 0);
|
||||
|
||||
error_code ec(boost::system::errc::no_such_file_or_directory
|
||||
, generic_category());
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
mgr.emplace_alert<save_resume_data_failed_alert>(torrent_handle(), ec);
|
||||
|
||||
TEST_EQUAL(mgr.num_queued_resume(), 2);
|
||||
|
||||
mgr.get_all(alerts, num_resume);
|
||||
TEST_EQUAL(num_resume, 2);
|
||||
TEST_EQUAL(alerts.size(), 2);
|
||||
|
||||
TEST_EQUAL(mgr.num_queued_resume(), 0);
|
||||
}
|
||||
|
||||
TORRENT_TEST(alert_mask)
|
||||
{
|
||||
alert_manager mgr(100, 0xffffffff);
|
||||
|
|
|
@ -692,7 +692,6 @@ TORRENT_TEST(fastresume)
|
|||
return;
|
||||
|
||||
std::cerr << resume.to_string() << "\n";
|
||||
TEST_CHECK(resume.dict().find("file sizes") != resume.dict().end());
|
||||
|
||||
// make sure the fast resume check fails! since we removed the file
|
||||
{
|
||||
|
@ -795,7 +794,6 @@ TORRENT_TEST(rename_file_fastresume)
|
|||
TEST_CHECK(!exists(combine_path(test_path, "tmp2/temporary")));
|
||||
TEST_CHECK(exists(combine_path(test_path, "tmp2/testing_renamed_files")));
|
||||
TEST_CHECK(resume.dict().find("mapped_files") != resume.dict().end());
|
||||
TEST_CHECK(resume.dict().find("file sizes") != resume.dict().end());
|
||||
|
||||
std::cerr << resume.to_string() << "\n";
|
||||
|
||||
|
|
Loading…
Reference in New Issue