forked from premiere/premiere-libtorrent
Merge pull request #402 from arvidn/resume-data-no-timestamps
Resume data no timestamps
This commit is contained in:
commit
ee94ac6ef7
|
@ -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
|
||||
|
|
|
@ -35,13 +35,15 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -50,36 +52,52 @@ namespace libtorrent
|
|||
stat_cache();
|
||||
~stat_cache();
|
||||
|
||||
void init(int num_files);
|
||||
void reserve(int num_files);
|
||||
|
||||
enum
|
||||
{
|
||||
cache_error = -1,
|
||||
not_in_cache = -2,
|
||||
no_exist = -3
|
||||
};
|
||||
// returns the size of the file unless an error occurs, in which case ec
|
||||
// is set to indicate the error
|
||||
boost::int64_t get_filesize(int i, file_storage const& fs
|
||||
, std::string const& save_path, error_code& ec);
|
||||
|
||||
// returns the size of the file or one
|
||||
// of the enums, noent or not_in_cache
|
||||
boost::int64_t get_filesize(int i) const;
|
||||
time_t get_filetime(int i) const;
|
||||
|
||||
void set_cache(int i, boost::int64_t size, time_t time);
|
||||
void set_noexist(int i);
|
||||
void set_error(int i);
|
||||
void set_dirty(int i);
|
||||
|
||||
void clear();
|
||||
|
||||
// internal
|
||||
enum
|
||||
{
|
||||
not_in_cache = -1,
|
||||
file_error = -2 // (first index in m_errors)
|
||||
};
|
||||
|
||||
// internal
|
||||
void set_cache(int i, boost::int64_t size);
|
||||
void set_error(int i, error_code const& ec);
|
||||
|
||||
private:
|
||||
|
||||
// returns the index to the specified error. Either an existing one or a
|
||||
// newly added entry
|
||||
int add_error(error_code const& ec);
|
||||
|
||||
struct stat_cache_t
|
||||
{
|
||||
stat_cache_t(boost::int64_t s, time_t t = 0): file_size(s), file_time(t) {}
|
||||
stat_cache_t(boost::int64_t s): file_size(s) {}
|
||||
|
||||
// the size of the file. Negative values have special meaning. -1 means
|
||||
// not-in-cache (i.e. there's no data for this file in the cache).
|
||||
// lower values (larger negative values) indicate that an error
|
||||
// occurred while stat()ing the file. The positive value is an index
|
||||
// into m_errors, that recorded the actual error.
|
||||
boost::int64_t file_size;
|
||||
time_t file_time;
|
||||
};
|
||||
|
||||
// one entry per file
|
||||
std::vector<stat_cache_t> m_stat_cache;
|
||||
|
||||
// These are the errors that have happened when stating files. Each entry
|
||||
// that had an error, refers to an index into this vector.
|
||||
std::vector<error_code> m_errors;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -32,19 +32,34 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/stat_cache.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class file_storage;
|
||||
|
||||
stat_cache::stat_cache() {}
|
||||
stat_cache::~stat_cache() {}
|
||||
|
||||
void stat_cache::set_cache(int i, boost::int64_t size, time_t time)
|
||||
void stat_cache::set_cache(int i, boost::int64_t size)
|
||||
{
|
||||
TORRENT_ASSERT(i >= 0);
|
||||
if (i >= int(m_stat_cache.size()))
|
||||
m_stat_cache.resize(i + 1, not_in_cache);
|
||||
m_stat_cache[i].file_size = size;
|
||||
m_stat_cache[i].file_time = time;
|
||||
}
|
||||
|
||||
void stat_cache::set_error(int i, error_code const& ec)
|
||||
{
|
||||
TORRENT_ASSERT(i >= 0);
|
||||
if (i >= int(m_stat_cache.size()))
|
||||
m_stat_cache.resize(i + 1, not_in_cache);
|
||||
|
||||
int error_index = add_error(ec);
|
||||
m_stat_cache[i].file_size = file_error - error_index;
|
||||
}
|
||||
|
||||
void stat_cache::set_dirty(int i)
|
||||
|
@ -54,36 +69,38 @@ namespace libtorrent
|
|||
m_stat_cache[i].file_size = not_in_cache;
|
||||
}
|
||||
|
||||
void stat_cache::set_noexist(int i)
|
||||
boost::int64_t stat_cache::get_filesize(int i, file_storage const& fs
|
||||
, std::string const& save_path, error_code& ec)
|
||||
{
|
||||
TORRENT_ASSERT(i >= 0);
|
||||
if (i >= int(m_stat_cache.size()))
|
||||
m_stat_cache.resize(i + 1, not_in_cache);
|
||||
m_stat_cache[i].file_size = no_exist;
|
||||
TORRENT_ASSERT(i < int(fs.num_files()));
|
||||
if (i >= int(m_stat_cache.size())) m_stat_cache.resize(i + 1, not_in_cache);
|
||||
boost::int64_t sz = m_stat_cache[i].file_size;
|
||||
if (sz < not_in_cache)
|
||||
{
|
||||
ec = m_errors[-sz + file_error];
|
||||
return file_error;
|
||||
}
|
||||
else if (sz == not_in_cache)
|
||||
{
|
||||
// query the filesystem
|
||||
file_status s;
|
||||
std::string file_path = fs.file_path(i, save_path);
|
||||
stat_file(file_path, &s, ec);
|
||||
if (ec)
|
||||
{
|
||||
set_error(i, ec);
|
||||
sz = file_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_cache(i, s.file_size);
|
||||
sz = s.file_size;
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void stat_cache::set_error(int i)
|
||||
{
|
||||
TORRENT_ASSERT(i >= 0);
|
||||
if (i >= int(m_stat_cache.size()))
|
||||
m_stat_cache.resize(i + 1, not_in_cache);
|
||||
m_stat_cache[i].file_size = cache_error;
|
||||
}
|
||||
|
||||
boost::int64_t stat_cache::get_filesize(int i) const
|
||||
{
|
||||
if (i >= int(m_stat_cache.size())) return not_in_cache;
|
||||
return m_stat_cache[i].file_size;
|
||||
}
|
||||
|
||||
time_t stat_cache::get_filetime(int i) const
|
||||
{
|
||||
if (i >= int(m_stat_cache.size())) return not_in_cache;
|
||||
if (m_stat_cache[i].file_size < 0) return m_stat_cache[i].file_size;
|
||||
return m_stat_cache[i].file_time;
|
||||
}
|
||||
|
||||
void stat_cache::init(int num_files)
|
||||
void stat_cache::reserve(int num_files)
|
||||
{
|
||||
m_stat_cache.resize(num_files, not_in_cache);
|
||||
}
|
||||
|
@ -91,7 +108,15 @@ namespace libtorrent
|
|||
void stat_cache::clear()
|
||||
{
|
||||
std::vector<stat_cache_t>().swap(m_stat_cache);
|
||||
std::vector<error_code>().swap(m_errors);
|
||||
}
|
||||
|
||||
int stat_cache::add_error(error_code const& ec)
|
||||
{
|
||||
std::vector<error_code>::iterator i = std::find(m_errors.begin(), m_errors.end(), ec);
|
||||
if (i != m_errors.end()) return i - m_errors.begin();
|
||||
m_errors.push_back(ec);
|
||||
return m_errors.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
351
src/storage.cpp
351
src/storage.cpp
|
@ -509,7 +509,7 @@ namespace libtorrent
|
|||
|
||||
void default_storage::initialize(storage_error& ec)
|
||||
{
|
||||
m_stat_cache.init(files().num_files());
|
||||
m_stat_cache.reserve(files().num_files());
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// don't do full file allocations on network drives
|
||||
|
@ -540,25 +540,22 @@ namespace libtorrent
|
|||
// ignore pad files
|
||||
if (files().pad_file_at(file_index)) continue;
|
||||
|
||||
if (m_stat_cache.get_filesize(file_index) == stat_cache::not_in_cache)
|
||||
error_code err;
|
||||
boost::int64_t size = m_stat_cache.get_filesize(file_index, files()
|
||||
, m_save_path, err);
|
||||
|
||||
if (err && err != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
file_status s;
|
||||
std::string file_path = files().file_path(file_index, m_save_path);
|
||||
stat_file(file_path, &s, ec.ec);
|
||||
if (ec && ec.ec != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
m_stat_cache.set_error(file_index);
|
||||
ec.file = file_index;
|
||||
ec.operation = storage_error::stat;
|
||||
ec.ec = err;
|
||||
break;
|
||||
}
|
||||
m_stat_cache.set_cache(file_index, s.file_size, s.mtime);
|
||||
}
|
||||
|
||||
// if the file already exists, but is larger than what
|
||||
// it's supposed to be, truncate it
|
||||
// if the file is empty, just create it either way.
|
||||
if ((!ec && m_stat_cache.get_filesize(file_index) > files().file_size(file_index))
|
||||
if ((!err && size > files().file_size(file_index))
|
||||
|| files().file_size(file_index) == 0)
|
||||
{
|
||||
std::string file_path = files().file_path(file_index, m_save_path);
|
||||
|
@ -579,9 +576,14 @@ namespace libtorrent
|
|||
ec.ec.clear();
|
||||
file_handle f = open_file(file_index, file::read_write
|
||||
| file::random_access, ec);
|
||||
if (ec) return;
|
||||
if (ec)
|
||||
{
|
||||
ec.file = file_index;
|
||||
ec.operation = storage_error::fallocate;
|
||||
return;
|
||||
}
|
||||
|
||||
boost::int64_t size = files().file_size(file_index);
|
||||
size = files().file_size(file_index);
|
||||
f->set_size(size, ec.ec);
|
||||
if (ec)
|
||||
{
|
||||
|
@ -589,8 +591,6 @@ namespace libtorrent
|
|||
ec.operation = storage_error::fallocate;
|
||||
break;
|
||||
}
|
||||
size_t mtime = m_stat_cache.get_filetime(file_index);
|
||||
m_stat_cache.set_cache(file_index, size, mtime);
|
||||
}
|
||||
ec.ec.clear();
|
||||
}
|
||||
|
@ -609,48 +609,37 @@ namespace libtorrent
|
|||
|
||||
bool default_storage::has_any_file(storage_error& ec)
|
||||
{
|
||||
m_stat_cache.init(files().num_files());
|
||||
m_stat_cache.reserve(files().num_files());
|
||||
|
||||
std::string file_path;
|
||||
for (int i = 0; i < files().num_files(); ++i)
|
||||
{
|
||||
file_status s;
|
||||
boost::int64_t cache_status = m_stat_cache.get_filesize(i);
|
||||
if (cache_status < 0 && cache_status != stat_cache::no_exist)
|
||||
{
|
||||
file_path = files().file_path(i, m_save_path);
|
||||
stat_file(file_path, &s, ec.ec);
|
||||
boost::int64_t r = s.file_size;
|
||||
if (ec.ec || !(s.mode & file_status::regular_file)) r = -1;
|
||||
boost::int64_t sz = m_stat_cache.get_filesize(
|
||||
i, files(), m_save_path, ec.ec);
|
||||
|
||||
if (ec && ec.ec == boost::system::errc::no_such_file_or_directory)
|
||||
if (sz < 0)
|
||||
{
|
||||
ec.ec.clear();
|
||||
r = -3;
|
||||
}
|
||||
m_stat_cache.set_cache(i, r, s.mtime);
|
||||
|
||||
if (ec)
|
||||
if (ec && ec.ec != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
m_stat_cache.clear();
|
||||
return false;
|
||||
}
|
||||
// some files not existing is expected and not an error
|
||||
ec.ec.clear();
|
||||
}
|
||||
|
||||
// if we didn't find the file, check the next one
|
||||
if (m_stat_cache.get_filesize(i) == stat_cache::no_exist) continue;
|
||||
|
||||
if (m_stat_cache.get_filesize(i) > 0)
|
||||
return true;
|
||||
if (sz > 0) return true;
|
||||
}
|
||||
file_status s;
|
||||
stat_file(combine_path(m_save_path, m_part_file_name), &s, ec.ec);
|
||||
if (!ec) return true;
|
||||
|
||||
// the part file not existing is expected
|
||||
if (ec && ec.ec == boost::system::errc::no_such_file_or_directory)
|
||||
ec.ec.clear();
|
||||
|
||||
if (ec)
|
||||
{
|
||||
ec.file = -1;
|
||||
|
@ -831,244 +820,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 +861,55 @@ 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;
|
||||
error_code error;
|
||||
boost::int64_t size = m_stat_cache.get_filesize(f[0].file_index
|
||||
, fs, m_save_path, error);
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
if (error != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
ec.ec = error;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.ec = errors::mismatching_file_size;
|
||||
ec.file = i;
|
||||
ec.operation = storage_error::stat;
|
||||
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 +1403,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 +1431,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);
|
||||
|
|
|
@ -42,39 +42,46 @@ TORRENT_TEST(stat_cache)
|
|||
|
||||
stat_cache sc;
|
||||
|
||||
sc.init(10);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
file_storage fs;
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
TEST_CHECK(sc.get_filesize(i) == stat_cache::not_in_cache);
|
||||
TEST_CHECK(sc.get_filetime(i) == stat_cache::not_in_cache);
|
||||
char buf[50];
|
||||
snprintf(buf, sizeof(buf), "test_torrent/test-%d", i);
|
||||
fs.add_file(buf, (i + 1) * 10);
|
||||
}
|
||||
|
||||
// out of bound accesses count as not-in-cache
|
||||
TEST_CHECK(sc.get_filesize(10) == stat_cache::not_in_cache);
|
||||
TEST_CHECK(sc.get_filesize(11) == stat_cache::not_in_cache);
|
||||
std::string save_path = ".";
|
||||
|
||||
sc.set_error(3);
|
||||
TEST_CHECK(sc.get_filesize(3) == stat_cache::cache_error);
|
||||
sc.reserve(10);
|
||||
|
||||
sc.set_noexist(3);
|
||||
TEST_CHECK(sc.get_filesize(3) == stat_cache::no_exist);
|
||||
sc.set_error(3, error_code(boost::system::errc::permission_denied, generic_category()));
|
||||
ec.clear();
|
||||
TEST_EQUAL(sc.get_filesize(3, fs, save_path, ec), stat_cache::file_error);
|
||||
TEST_EQUAL(ec, error_code(boost::system::errc::permission_denied, generic_category()));
|
||||
|
||||
sc.set_cache(3, 101, 5555);
|
||||
TEST_CHECK(sc.get_filesize(3) == 101);
|
||||
TEST_CHECK(sc.get_filetime(3) == 5555);
|
||||
sc.set_error(3, error_code(boost::system::errc::no_such_file_or_directory, generic_category()));
|
||||
ec.clear();
|
||||
TEST_EQUAL(sc.get_filesize(3, fs, save_path, ec), stat_cache::file_error);
|
||||
TEST_EQUAL(ec, error_code(boost::system::errc::no_such_file_or_directory, generic_category()));
|
||||
|
||||
sc.set_error(11);
|
||||
TEST_CHECK(sc.get_filesize(10) == stat_cache::not_in_cache);
|
||||
TEST_CHECK(sc.get_filesize(11) == stat_cache::cache_error);
|
||||
ec.clear();
|
||||
sc.set_cache(3, 101);
|
||||
TEST_EQUAL(sc.get_filesize(3, fs, save_path, ec), 101);
|
||||
TEST_CHECK(!ec);
|
||||
|
||||
sc.set_noexist(13);
|
||||
TEST_CHECK(sc.get_filesize(12) == stat_cache::not_in_cache);
|
||||
TEST_CHECK(sc.get_filesize(13) == stat_cache::no_exist);
|
||||
sc.set_error(11, error_code(boost::system::errc::broken_pipe, generic_category()));
|
||||
ec.clear();
|
||||
TEST_EQUAL(sc.get_filesize(11, fs, save_path, ec), stat_cache::file_error);
|
||||
TEST_EQUAL(ec, error_code(boost::system::errc::broken_pipe, generic_category()));
|
||||
|
||||
sc.set_cache(15, 1000, 3000);
|
||||
TEST_CHECK(sc.get_filesize(14) == stat_cache::not_in_cache);
|
||||
TEST_CHECK(sc.get_filesize(15) == 1000);
|
||||
TEST_CHECK(sc.get_filetime(15) == 3000);
|
||||
ec.clear();
|
||||
sc.set_error(13, error_code(boost::system::errc::no_such_file_or_directory, generic_category()));
|
||||
TEST_EQUAL(sc.get_filesize(13, fs, save_path, ec), stat_cache::file_error);
|
||||
TEST_EQUAL(ec, error_code(boost::system::errc::no_such_file_or_directory, generic_category()));
|
||||
|
||||
ec.clear();
|
||||
sc.set_cache(15, 1000);
|
||||
TEST_CHECK(sc.get_filesize(15, fs, save_path, ec) == 1000);
|
||||
TEST_CHECK(!ec);
|
||||
}
|
||||
|
||||
|
|
|
@ -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