lt sync 1677
This commit is contained in:
parent
a16eb7625c
commit
b02b71e978
|
@ -87,10 +87,10 @@ namespace
|
||||||
|
|
||||||
torrent_handle add_torrent(session& s, torrent_info const& ti
|
torrent_handle add_torrent(session& s, torrent_info const& ti
|
||||||
, boost::filesystem::path const& save, entry const& resume
|
, boost::filesystem::path const& save, entry const& resume
|
||||||
, bool compact, bool paused)
|
, storage_mode_t storage_mode, bool paused)
|
||||||
{
|
{
|
||||||
allow_threading_guard guard;
|
allow_threading_guard guard;
|
||||||
return s.add_torrent(ti, save, resume, compact, paused, default_storage_constructor);
|
return s.add_torrent(ti, save, resume, storage_mode, paused, default_storage_constructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace unnamed
|
} // namespace unnamed
|
||||||
|
@ -154,6 +154,17 @@ void bind_session()
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
enum_<storage_mode_t>("storage_mode_t")
|
||||||
|
.value("storage_mode_allocate", storage_mode_allocate)
|
||||||
|
.value("storage_mode_compact", storage_mode_compact)
|
||||||
|
.value("storage_mode_sparse", storage_mode_sparse)
|
||||||
|
;
|
||||||
|
|
||||||
|
enum_<session::options_t>("options_t")
|
||||||
|
.value("none", session::none)
|
||||||
|
.value("delete_files", session::delete_files)
|
||||||
|
;
|
||||||
|
|
||||||
class_<session, boost::noncopyable>("session", session_doc, no_init)
|
class_<session, boost::noncopyable>("session", session_doc, no_init)
|
||||||
.def(
|
.def(
|
||||||
init<fingerprint>(arg("fingerprint")=fingerprint("LT",0,1,0,0), session_init_doc)
|
init<fingerprint>(arg("fingerprint")=fingerprint("LT",0,1,0,0), session_init_doc)
|
||||||
|
@ -235,8 +246,6 @@ void bind_session()
|
||||||
.def("stop_natpmp", allow_threads(&session::stop_natpmp), session_stop_natpmp_doc)
|
.def("stop_natpmp", allow_threads(&session::stop_natpmp), session_stop_natpmp_doc)
|
||||||
;
|
;
|
||||||
|
|
||||||
def("supports_sparse_files", &supports_sparse_files);
|
|
||||||
|
|
||||||
register_ptr_to_python<std::auto_ptr<alert> >();
|
register_ptr_to_python<std::auto_ptr<alert> >();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,16 @@ namespace libtorrent
|
||||||
{ return std::auto_ptr<alert>(new storage_moved_alert(*this)); }
|
{ return std::auto_ptr<alert>(new storage_moved_alert(*this)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TORRENT_EXPORT torrent_deleted_alert: torrent_alert
|
||||||
|
{
|
||||||
|
torrent_deleted_alert(torrent_handle const& h, std::string const& msg)
|
||||||
|
: torrent_alert(h, alert::warning, msg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual std::auto_ptr<alert> clone() const
|
||||||
|
{ return std::auto_ptr<alert>(new torrent_deleted_alert(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
|
struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
|
||||||
{
|
{
|
||||||
torrent_paused_alert(torrent_handle const& h, std::string const& msg)
|
torrent_paused_alert(torrent_handle const& h, std::string const& msg)
|
||||||
|
|
|
@ -140,7 +140,7 @@ namespace libtorrent
|
||||||
checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
|
checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
|
||||||
void operator()();
|
void operator()();
|
||||||
piece_checker_data* find_torrent(const sha1_hash& info_hash);
|
piece_checker_data* find_torrent(const sha1_hash& info_hash);
|
||||||
void remove_torrent(sha1_hash const& info_hash);
|
void remove_torrent(sha1_hash const& info_hash, int options);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void check_invariant() const;
|
void check_invariant() const;
|
||||||
|
@ -254,7 +254,7 @@ namespace libtorrent
|
||||||
boost::intrusive_ptr<torrent_info> ti
|
boost::intrusive_ptr<torrent_info> ti
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data
|
, entry const& resume_data
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused
|
, bool paused
|
||||||
, void* userdata);
|
, void* userdata);
|
||||||
|
@ -265,12 +265,12 @@ namespace libtorrent
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data
|
, entry const& resume_data
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused
|
, bool paused
|
||||||
, void* userdata);
|
, void* userdata);
|
||||||
|
|
||||||
void remove_torrent(torrent_handle const& h);
|
void remove_torrent(torrent_handle const& h, int options);
|
||||||
|
|
||||||
std::vector<torrent_handle> get_torrents();
|
std::vector<torrent_handle> get_torrents();
|
||||||
|
|
||||||
|
@ -371,12 +371,6 @@ namespace libtorrent
|
||||||
|
|
||||||
void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
|
void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
|
||||||
|
|
||||||
// handles disk io requests asynchronously
|
|
||||||
// peers have pointers into the disk buffer
|
|
||||||
// pool, and must be destructed before this
|
|
||||||
// object.
|
|
||||||
disk_io_thread m_disk_thread;
|
|
||||||
|
|
||||||
// this pool is used to allocate and recycle send
|
// this pool is used to allocate and recycle send
|
||||||
// buffers from.
|
// buffers from.
|
||||||
boost::pool<> m_send_buffers;
|
boost::pool<> m_send_buffers;
|
||||||
|
@ -395,6 +389,12 @@ namespace libtorrent
|
||||||
// when they are destructed.
|
// when they are destructed.
|
||||||
file_pool m_files;
|
file_pool m_files;
|
||||||
|
|
||||||
|
// handles disk io requests asynchronously
|
||||||
|
// peers have pointers into the disk buffer
|
||||||
|
// pool, and must be destructed before this
|
||||||
|
// object.
|
||||||
|
disk_io_thread m_disk_thread;
|
||||||
|
|
||||||
// this is a list of half-open tcp connections
|
// this is a list of half-open tcp connections
|
||||||
// (only outgoing connections)
|
// (only outgoing connections)
|
||||||
// this has to be one of the last
|
// this has to be one of the last
|
||||||
|
|
|
@ -64,6 +64,7 @@ namespace libtorrent
|
||||||
, hash
|
, hash
|
||||||
, move_storage
|
, move_storage
|
||||||
, release_files
|
, release_files
|
||||||
|
, delete_files
|
||||||
};
|
};
|
||||||
|
|
||||||
action_t action;
|
action_t action;
|
||||||
|
|
|
@ -176,7 +176,7 @@ namespace libtorrent
|
||||||
void set_non_prioritized(bool b)
|
void set_non_prioritized(bool b)
|
||||||
{ m_non_prioritized = b; }
|
{ m_non_prioritized = b; }
|
||||||
|
|
||||||
void fast_reconnect(bool r) { m_fast_reconnect = r; }
|
void fast_reconnect(bool r);
|
||||||
bool fast_reconnect() const { return m_fast_reconnect; }
|
bool fast_reconnect() const { return m_fast_reconnect; }
|
||||||
|
|
||||||
// this adds an announcement in the announcement queue
|
// this adds an announcement in the announcement queue
|
||||||
|
|
|
@ -156,6 +156,8 @@ namespace libtorrent
|
||||||
// this is true if the peer is a seed
|
// this is true if the peer is a seed
|
||||||
bool seed;
|
bool seed;
|
||||||
|
|
||||||
|
int fast_reconnects;
|
||||||
|
|
||||||
// true if this peer currently is unchoked
|
// true if this peer currently is unchoked
|
||||||
// because of an optimistic unchoke.
|
// because of an optimistic unchoke.
|
||||||
// when the optimistic unchoke is moved to
|
// when the optimistic unchoke is moved to
|
||||||
|
|
|
@ -140,7 +140,7 @@ namespace libtorrent
|
||||||
torrent_info const& ti
|
torrent_info const& ti
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data = entry()
|
, entry const& resume_data = entry()
|
||||||
, bool compact_mode = true
|
, storage_mode_t storage_mode = storage_mode_sparse
|
||||||
, bool paused = false
|
, bool paused = false
|
||||||
, storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED;
|
, storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ namespace libtorrent
|
||||||
boost::intrusive_ptr<torrent_info> ti
|
boost::intrusive_ptr<torrent_info> ti
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data = entry()
|
, entry const& resume_data = entry()
|
||||||
, bool compact_mode = true
|
, storage_mode_t storage_mode = storage_mode_sparse
|
||||||
, bool paused = false
|
, bool paused = false
|
||||||
, storage_constructor_type sc = default_storage_constructor
|
, storage_constructor_type sc = default_storage_constructor
|
||||||
, void* userdata = 0);
|
, void* userdata = 0);
|
||||||
|
@ -159,7 +159,7 @@ namespace libtorrent
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data = entry()
|
, entry const& resume_data = entry()
|
||||||
, bool compact_mode = true
|
, storage_mode_t storage_mode = storage_mode_sparse
|
||||||
, bool paused = false
|
, bool paused = false
|
||||||
, storage_constructor_type sc = default_storage_constructor
|
, storage_constructor_type sc = default_storage_constructor
|
||||||
, void* userdata = 0);
|
, void* userdata = 0);
|
||||||
|
@ -219,7 +219,13 @@ namespace libtorrent
|
||||||
// number of half open connections.
|
// number of half open connections.
|
||||||
int num_connections() const;
|
int num_connections() const;
|
||||||
|
|
||||||
void remove_torrent(const torrent_handle& h);
|
enum options_t
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
delete_files = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
void remove_torrent(const torrent_handle& h, int options = none);
|
||||||
|
|
||||||
void set_settings(session_settings const& s);
|
void set_settings(session_settings const& s);
|
||||||
session_settings const& settings();
|
session_settings const& settings();
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace libtorrent
|
||||||
, allow_multiple_connections_per_ip(false)
|
, allow_multiple_connections_per_ip(false)
|
||||||
, max_failcount(3)
|
, max_failcount(3)
|
||||||
, min_reconnect_time(60)
|
, min_reconnect_time(60)
|
||||||
, peer_connect_timeout(10)
|
, peer_connect_timeout(7)
|
||||||
, ignore_limits_on_local_network(true)
|
, ignore_limits_on_local_network(true)
|
||||||
, connection_speed(20)
|
, connection_speed(20)
|
||||||
, send_redundant_have(false)
|
, send_redundant_have(false)
|
||||||
|
|
|
@ -71,6 +71,13 @@ namespace libtorrent
|
||||||
struct file_pool;
|
struct file_pool;
|
||||||
struct disk_io_job;
|
struct disk_io_job;
|
||||||
|
|
||||||
|
enum storage_mode_t
|
||||||
|
{
|
||||||
|
storage_mode_allocate = 0,
|
||||||
|
storage_mode_sparse,
|
||||||
|
storage_mode_compact
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(UNICODE)
|
#if defined(_WIN32) && defined(UNICODE)
|
||||||
|
|
||||||
TORRENT_EXPORT std::wstring safe_convert(std::string const& s);
|
TORRENT_EXPORT std::wstring safe_convert(std::string const& s);
|
||||||
|
@ -144,6 +151,10 @@ namespace libtorrent
|
||||||
// writing. This is called when a torrent has finished
|
// writing. This is called when a torrent has finished
|
||||||
// downloading.
|
// downloading.
|
||||||
virtual void release_files() = 0;
|
virtual void release_files() = 0;
|
||||||
|
|
||||||
|
// this will close all open files and delete them
|
||||||
|
virtual void delete_files() = 0;
|
||||||
|
|
||||||
virtual ~storage_interface() {}
|
virtual ~storage_interface() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -155,10 +166,6 @@ namespace libtorrent
|
||||||
boost::intrusive_ptr<torrent_info const> ti
|
boost::intrusive_ptr<torrent_info const> ti
|
||||||
, fs::path const& path, file_pool& fp);
|
, fs::path const& path, file_pool& fp);
|
||||||
|
|
||||||
// returns true if the filesystem the path relies on supports
|
|
||||||
// sparse files or automatic zero filling of files.
|
|
||||||
TORRENT_EXPORT bool supports_sparse_files(fs::path const& p);
|
|
||||||
|
|
||||||
struct disk_io_thread;
|
struct disk_io_thread;
|
||||||
|
|
||||||
class TORRENT_EXPORT piece_manager
|
class TORRENT_EXPORT piece_manager
|
||||||
|
@ -180,7 +187,8 @@ namespace libtorrent
|
||||||
~piece_manager();
|
~piece_manager();
|
||||||
|
|
||||||
bool check_fastresume(aux::piece_checker_data& d
|
bool check_fastresume(aux::piece_checker_data& d
|
||||||
, std::vector<bool>& pieces, int& num_pieces, bool compact_mode);
|
, std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode
|
||||||
|
, std::string& error_msg);
|
||||||
std::pair<bool, float> check_files(std::vector<bool>& pieces
|
std::pair<bool, float> check_files(std::vector<bool>& pieces
|
||||||
, int& num_pieces, boost::recursive_mutex& mutex);
|
, int& num_pieces, boost::recursive_mutex& mutex);
|
||||||
|
|
||||||
|
@ -191,7 +199,7 @@ namespace libtorrent
|
||||||
bool verify_resume_data(entry& rd, std::string& error);
|
bool verify_resume_data(entry& rd, std::string& error);
|
||||||
|
|
||||||
bool is_allocating() const
|
bool is_allocating() const
|
||||||
{ return m_state == state_allocating; }
|
{ return m_state == state_expand_pieces; }
|
||||||
|
|
||||||
void mark_failed(int index);
|
void mark_failed(int index);
|
||||||
|
|
||||||
|
@ -200,7 +208,8 @@ namespace libtorrent
|
||||||
, int block_size
|
, int block_size
|
||||||
, piece_picker::block_info const* bi);
|
, piece_picker::block_info const* bi);
|
||||||
|
|
||||||
int slot_for_piece(int piece_index) const;
|
int slot_for(int piece) const;
|
||||||
|
int piece_for(int slot) const;
|
||||||
|
|
||||||
void async_read(
|
void async_read(
|
||||||
peer_request const& r
|
peer_request const& r
|
||||||
|
@ -221,6 +230,10 @@ namespace libtorrent
|
||||||
boost::function<void(int, disk_io_job const&)> const& handler
|
boost::function<void(int, disk_io_job const&)> const& handler
|
||||||
= boost::function<void(int, disk_io_job const&)>());
|
= boost::function<void(int, disk_io_job const&)>());
|
||||||
|
|
||||||
|
void async_delete_files(
|
||||||
|
boost::function<void(int, disk_io_job const&)> const& handler
|
||||||
|
= boost::function<void(int, disk_io_job const&)>());
|
||||||
|
|
||||||
void async_move_storage(fs::path const& p
|
void async_move_storage(fs::path const& p
|
||||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||||
|
|
||||||
|
@ -228,10 +241,11 @@ namespace libtorrent
|
||||||
// slots to the piece that is stored (or
|
// slots to the piece that is stored (or
|
||||||
// partially stored) there. -2 is the index
|
// partially stored) there. -2 is the index
|
||||||
// of unassigned pieces and -1 is unallocated
|
// of unassigned pieces and -1 is unallocated
|
||||||
void export_piece_map(std::vector<int>& pieces) const;
|
void export_piece_map(std::vector<int>& pieces
|
||||||
|
, std::vector<bool> const& have) const;
|
||||||
|
|
||||||
bool compact_allocation() const
|
bool compact_allocation() const
|
||||||
{ return m_compact_mode; }
|
{ return m_storage_mode == storage_mode_compact; }
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::string name() const { return m_info->name(); }
|
std::string name() const { return m_info->name(); }
|
||||||
|
@ -261,9 +275,11 @@ namespace libtorrent
|
||||||
, int offset
|
, int offset
|
||||||
, int size);
|
, int size);
|
||||||
|
|
||||||
|
void switch_to_full_mode();
|
||||||
sha1_hash hash_for_piece_impl(int piece);
|
sha1_hash hash_for_piece_impl(int piece);
|
||||||
|
|
||||||
void release_files_impl();
|
void release_files_impl() { m_storage->release_files(); }
|
||||||
|
void delete_files_impl() { m_storage->delete_files(); }
|
||||||
|
|
||||||
bool move_storage_impl(fs::path const& save_path);
|
bool move_storage_impl(fs::path const& save_path);
|
||||||
|
|
||||||
|
@ -276,19 +292,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
boost::scoped_ptr<storage_interface> m_storage;
|
boost::scoped_ptr<storage_interface> m_storage;
|
||||||
|
|
||||||
// if this is true, pieces are always allocated at the
|
storage_mode_t m_storage_mode;
|
||||||
// lowest possible slot index. If it is false, pieces
|
|
||||||
// are always written to their final place immediately
|
|
||||||
bool m_compact_mode;
|
|
||||||
|
|
||||||
// if this is true, pieces that haven't been downloaded
|
|
||||||
// will be filled with zeroes. Not filling with zeroes
|
|
||||||
// will not work in some cases (where a seek cannot pass
|
|
||||||
// the end of the file).
|
|
||||||
bool m_fill_mode;
|
|
||||||
|
|
||||||
// a bitmask representing the pieces we have
|
|
||||||
std::vector<bool> m_have_piece;
|
|
||||||
|
|
||||||
boost::intrusive_ptr<torrent_info const> m_info;
|
boost::intrusive_ptr<torrent_info const> m_info;
|
||||||
|
|
||||||
|
@ -329,10 +333,21 @@ namespace libtorrent
|
||||||
state_create_files,
|
state_create_files,
|
||||||
// checking the files
|
// checking the files
|
||||||
state_full_check,
|
state_full_check,
|
||||||
// allocating files (in non-compact mode)
|
// move pieces to their final position
|
||||||
state_allocating
|
state_expand_pieces
|
||||||
} m_state;
|
} m_state;
|
||||||
int m_current_slot;
|
int m_current_slot;
|
||||||
|
// used during check. If any piece is found
|
||||||
|
// that is not in its final position, this
|
||||||
|
// is set to true
|
||||||
|
bool m_out_of_place;
|
||||||
|
// used to move pieces while expanding
|
||||||
|
// the storage from compact allocation
|
||||||
|
// to full allocation
|
||||||
|
std::vector<char> m_scratch_buffer;
|
||||||
|
std::vector<char> m_scratch_buffer2;
|
||||||
|
// the piece that is in the scratch buffer
|
||||||
|
int m_scratch_piece;
|
||||||
|
|
||||||
// this is saved in case we need to instantiate a new
|
// this is saved in case we need to instantiate a new
|
||||||
// storage (osed when remapping files)
|
// storage (osed when remapping files)
|
||||||
|
|
|
@ -101,7 +101,7 @@ namespace libtorrent
|
||||||
, boost::intrusive_ptr<torrent_info> tf
|
, boost::intrusive_ptr<torrent_info> tf
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, bool compact_mode
|
, storage_mode_t m_storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused);
|
, bool paused);
|
||||||
|
@ -116,7 +116,7 @@ namespace libtorrent
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, bool compact_mode
|
, storage_mode_t m_storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused);
|
, bool paused);
|
||||||
|
@ -177,6 +177,8 @@ namespace libtorrent
|
||||||
void resume();
|
void resume();
|
||||||
bool is_paused() const { return m_paused; }
|
bool is_paused() const { return m_paused; }
|
||||||
|
|
||||||
|
void delete_files();
|
||||||
|
|
||||||
// ============ start deprecation =============
|
// ============ start deprecation =============
|
||||||
void filter_piece(int index, bool filter);
|
void filter_piece(int index, bool filter);
|
||||||
void filter_pieces(std::vector<bool> const& bitmask);
|
void filter_pieces(std::vector<bool> const& bitmask);
|
||||||
|
@ -550,6 +552,7 @@ namespace libtorrent
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void on_files_deleted(int ret, disk_io_job const& j);
|
||||||
void on_files_released(int ret, disk_io_job const& j);
|
void on_files_released(int ret, disk_io_job const& j);
|
||||||
void on_torrent_paused(int ret, disk_io_job const& j);
|
void on_torrent_paused(int ret, disk_io_job const& j);
|
||||||
void on_storage_moved(int ret, disk_io_job const& j);
|
void on_storage_moved(int ret, disk_io_job const& j);
|
||||||
|
@ -751,7 +754,7 @@ namespace libtorrent
|
||||||
fs::path m_save_path;
|
fs::path m_save_path;
|
||||||
|
|
||||||
// determines the storage state for this torrent.
|
// determines the storage state for this torrent.
|
||||||
const bool m_compact_mode;
|
storage_mode_t m_storage_mode;
|
||||||
|
|
||||||
// defaults to 16 kiB, but can be set by the user
|
// defaults to 16 kiB, but can be set by the user
|
||||||
// when creating the torrent
|
// when creating the torrent
|
||||||
|
|
|
@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/storage.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -106,7 +107,7 @@ namespace libtorrent
|
||||||
, num_connections(0)
|
, num_connections(0)
|
||||||
, uploads_limit(0)
|
, uploads_limit(0)
|
||||||
, connections_limit(0)
|
, connections_limit(0)
|
||||||
, compact_mode(false)
|
, storage_mode(storage_mode_sparse)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
enum state_t
|
enum state_t
|
||||||
|
@ -216,7 +217,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// true if the torrent is saved in compact mode
|
// true if the torrent is saved in compact mode
|
||||||
// false if it is saved in full allocation mode
|
// false if it is saved in full allocation mode
|
||||||
bool compact_mode;
|
storage_mode_t storage_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT block_info
|
struct TORRENT_EXPORT block_info
|
||||||
|
|
|
@ -204,7 +204,6 @@ namespace libtorrent
|
||||||
|
|
||||||
// if this fails, we need to reconnect
|
// if this fails, we need to reconnect
|
||||||
// fast.
|
// fast.
|
||||||
pi->connected = time_now() - seconds(m_ses.settings().min_reconnect_time);
|
|
||||||
fast_reconnect(true);
|
fast_reconnect(true);
|
||||||
|
|
||||||
write_pe1_2_dhkey();
|
write_pe1_2_dhkey();
|
||||||
|
@ -802,9 +801,9 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
TORRENT_ASSERT(t);
|
TORRENT_ASSERT(t);
|
||||||
while (!request_queue().empty())
|
while (!download_queue().empty())
|
||||||
{
|
{
|
||||||
piece_block const& b = request_queue().front();
|
piece_block const& b = download_queue().front();
|
||||||
peer_request r;
|
peer_request r;
|
||||||
r.piece = b.piece_index;
|
r.piece = b.piece_index;
|
||||||
r.start = b.block_index * t->block_size();
|
r.start = b.block_index * t->block_size();
|
||||||
|
|
|
@ -125,6 +125,7 @@ namespace libtorrent
|
||||||
, boost::function<void(int, disk_io_job const&)> const& f)
|
, boost::function<void(int, disk_io_job const&)> const& f)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(!j.callback);
|
TORRENT_ASSERT(!j.callback);
|
||||||
|
TORRENT_ASSERT(j.storage);
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
|
std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
|
||||||
|
@ -220,6 +221,7 @@ namespace libtorrent
|
||||||
bool free_buffer = true;
|
bool free_buffer = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
TORRENT_ASSERT(j.storage);
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
ptime start = time_now();
|
ptime start = time_now();
|
||||||
#endif
|
#endif
|
||||||
|
@ -288,6 +290,12 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
j.storage->release_files_impl();
|
j.storage->release_files_impl();
|
||||||
break;
|
break;
|
||||||
|
case disk_io_job::delete_files:
|
||||||
|
#ifdef TORRENT_DISK_STATS
|
||||||
|
m_log << log_time() << " delete" << std::endl;
|
||||||
|
#endif
|
||||||
|
j.storage->delete_files_impl();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
|
|
@ -394,6 +394,16 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void peer_connection::fast_reconnect(bool r)
|
||||||
|
{
|
||||||
|
if (peer_info_struct() && peer_info_struct()->fast_reconnects > 1) return;
|
||||||
|
m_fast_reconnect = r;
|
||||||
|
peer_info_struct()->connected = time_now()
|
||||||
|
- seconds(m_ses.settings().min_reconnect_time
|
||||||
|
* m_ses.settings().max_failcount);
|
||||||
|
if (peer_info_struct()) ++peer_info_struct()->fast_reconnects;
|
||||||
|
}
|
||||||
|
|
||||||
void peer_connection::announce_piece(int index)
|
void peer_connection::announce_piece(int index)
|
||||||
{
|
{
|
||||||
// dont announce during handshake
|
// dont announce during handshake
|
||||||
|
@ -643,16 +653,13 @@ namespace libtorrent
|
||||||
m_peer_choked = true;
|
m_peer_choked = true;
|
||||||
t->get_policy().choked(*this);
|
t->get_policy().choked(*this);
|
||||||
|
|
||||||
|
if (peer_info_struct() == 0 || !peer_info_struct()->on_parole)
|
||||||
|
{
|
||||||
|
// if the peer is not in parole mode, clear the queued
|
||||||
|
// up block requests
|
||||||
if (!t->is_seed())
|
if (!t->is_seed())
|
||||||
{
|
{
|
||||||
piece_picker& p = t->picker();
|
piece_picker& p = t->picker();
|
||||||
// remove all pieces from this peers download queue and
|
|
||||||
// remove the 'downloading' flag from piece_picker.
|
|
||||||
for (std::deque<piece_block>::iterator i = m_download_queue.begin();
|
|
||||||
i != m_download_queue.end(); ++i)
|
|
||||||
{
|
|
||||||
p.abort_download(*i);
|
|
||||||
}
|
|
||||||
for (std::deque<piece_block>::const_iterator i = m_request_queue.begin()
|
for (std::deque<piece_block>::const_iterator i = m_request_queue.begin()
|
||||||
, end(m_request_queue.end()); i != end; ++i)
|
, end(m_request_queue.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
|
@ -661,10 +668,9 @@ namespace libtorrent
|
||||||
p.abort_download(*i);
|
p.abort_download(*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_download_queue.clear();
|
|
||||||
m_request_queue.clear();
|
m_request_queue.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool match_request(peer_request const& r, piece_block const& b, int block_size)
|
bool match_request(peer_request const& r, piece_block const& b, int block_size)
|
||||||
{
|
{
|
||||||
|
@ -707,24 +713,18 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
b = *i;
|
b = *i;
|
||||||
m_download_queue.erase(i);
|
m_download_queue.erase(i);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i = std::find_if(m_request_queue.begin(), m_request_queue.end()
|
|
||||||
, bind(match_request, boost::cref(r), _1, t->block_size()));
|
|
||||||
|
|
||||||
if (i != m_request_queue.end())
|
// if the peer is in parole mode, keep the request
|
||||||
|
if (peer_info_struct() && peer_info_struct()->on_parole)
|
||||||
{
|
{
|
||||||
b = *i;
|
m_request_queue.push_front(b);
|
||||||
m_request_queue.erase(i);
|
|
||||||
}
|
}
|
||||||
}
|
else if (!t->is_seed())
|
||||||
|
|
||||||
if (b.piece_index != -1 && !t->is_seed())
|
|
||||||
{
|
{
|
||||||
piece_picker& p = t->picker();
|
piece_picker& p = t->picker();
|
||||||
p.abort_download(b);
|
p.abort_download(b);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1932,7 +1932,6 @@ namespace libtorrent
|
||||||
|
|
||||||
void peer_connection::timed_out()
|
void peer_connection::timed_out()
|
||||||
{
|
{
|
||||||
if (m_peer_info) ++m_peer_info->failcount;
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
(*m_ses.m_logger) << "CONNECTION TIMED OUT: " << m_remote.address().to_string()
|
(*m_ses.m_logger) << "CONNECTION TIMED OUT: " << m_remote.address().to_string()
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
|
@ -1732,7 +1732,6 @@ namespace libtorrent
|
||||||
++i->writing;
|
++i->writing;
|
||||||
info.state = block_info::state_writing;
|
info.state = block_info::state_writing;
|
||||||
if (info.num_peers > 0) --info.num_peers;
|
if (info.num_peers > 0) --info.num_peers;
|
||||||
TORRENT_ASSERT(info.num_peers >= 0);
|
|
||||||
|
|
||||||
if (i->requested == 0)
|
if (i->requested == 0)
|
||||||
{
|
{
|
||||||
|
@ -1855,7 +1854,6 @@ namespace libtorrent
|
||||||
|
|
||||||
block_info& info = i->info[block.block_index];
|
block_info& info = i->info[block.block_index];
|
||||||
--info.num_peers;
|
--info.num_peers;
|
||||||
TORRENT_ASSERT(info.num_peers >= 0);
|
|
||||||
if (info.num_peers > 0) return;
|
if (info.num_peers > 0) return;
|
||||||
|
|
||||||
if (i->info[block.block_index].state == block_info::state_finished
|
if (i->info[block.block_index].state == block_info::state_finished
|
||||||
|
|
|
@ -986,6 +986,7 @@ namespace libtorrent
|
||||||
i->second.prev_amount_upload = 0;
|
i->second.prev_amount_upload = 0;
|
||||||
i->second.connection = &c;
|
i->second.connection = &c;
|
||||||
TORRENT_ASSERT(i->second.connection);
|
TORRENT_ASSERT(i->second.connection);
|
||||||
|
if (!c.fast_reconnect())
|
||||||
i->second.connected = time_now();
|
i->second.connected = time_now();
|
||||||
// m_last_optimistic_disconnect = time_now();
|
// m_last_optimistic_disconnect = time_now();
|
||||||
}
|
}
|
||||||
|
@ -1045,10 +1046,10 @@ namespace libtorrent
|
||||||
|
|
||||||
// we don't have any info about this peer.
|
// we don't have any info about this peer.
|
||||||
// add a new entry
|
// add a new entry
|
||||||
peer p(remote, peer::connectable, src);
|
i = m_peers.insert(std::make_pair(remote.address()
|
||||||
i = m_peers.insert(std::make_pair(remote.address(), p));
|
, peer(remote, peer::connectable, src)));
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
if (flags & 0x01) p.pe_support = true;
|
if (flags & 0x01) i->second.pe_support = true;
|
||||||
#endif
|
#endif
|
||||||
if (flags & 0x02) i->second.seed = true;
|
if (flags & 0x02) i->second.seed = true;
|
||||||
|
|
||||||
|
@ -1503,6 +1504,7 @@ namespace libtorrent
|
||||||
, failcount(0)
|
, failcount(0)
|
||||||
, hashfails(0)
|
, hashfails(0)
|
||||||
, seed(false)
|
, seed(false)
|
||||||
|
, fast_reconnects(0)
|
||||||
, optimistically_unchoked(false)
|
, optimistically_unchoked(false)
|
||||||
, last_optimistically_unchoked(min_time())
|
, last_optimistically_unchoked(min_time())
|
||||||
, connected(min_time())
|
, connected(min_time())
|
||||||
|
|
|
@ -186,28 +186,28 @@ namespace libtorrent
|
||||||
torrent_info const& ti
|
torrent_info const& ti
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data
|
, entry const& resume_data
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, bool paused
|
, bool paused
|
||||||
, storage_constructor_type sc)
|
, storage_constructor_type sc)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(!ti.m_half_metadata);
|
TORRENT_ASSERT(!ti.m_half_metadata);
|
||||||
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
|
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
|
||||||
return m_impl->add_torrent(tip, save_path, resume_data
|
return m_impl->add_torrent(tip, save_path, resume_data
|
||||||
, compact_mode, sc, paused, 0);
|
, storage_mode, sc, paused, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_handle session::add_torrent(
|
torrent_handle session::add_torrent(
|
||||||
boost::intrusive_ptr<torrent_info> ti
|
boost::intrusive_ptr<torrent_info> ti
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data
|
, entry const& resume_data
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, bool paused
|
, bool paused
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, void* userdata)
|
, void* userdata)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(!ti->m_half_metadata);
|
TORRENT_ASSERT(!ti->m_half_metadata);
|
||||||
return m_impl->add_torrent(ti, save_path, resume_data
|
return m_impl->add_torrent(ti, save_path, resume_data
|
||||||
, compact_mode, sc, paused, userdata);
|
, storage_mode, sc, paused, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_handle session::add_torrent(
|
torrent_handle session::add_torrent(
|
||||||
|
@ -216,18 +216,18 @@ namespace libtorrent
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& e
|
, entry const& e
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, bool paused
|
, bool paused
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, void* userdata)
|
, void* userdata)
|
||||||
{
|
{
|
||||||
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
|
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
|
||||||
, compact_mode, sc, paused, userdata);
|
, storage_mode, sc, paused, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void session::remove_torrent(const torrent_handle& h)
|
void session::remove_torrent(const torrent_handle& h, int options)
|
||||||
{
|
{
|
||||||
m_impl->remove_torrent(h);
|
m_impl->remove_torrent(h, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool session::listen_on(
|
bool session::listen_on(
|
||||||
|
|
|
@ -189,9 +189,11 @@ namespace detail
|
||||||
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file()
|
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file()
|
||||||
, error_msg);
|
, error_msg);
|
||||||
|
|
||||||
|
// lock the session to add the new torrent
|
||||||
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
|
||||||
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
|
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
|
||||||
{
|
{
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
||||||
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
|
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
|
||||||
t->torrent_ptr->get_handle()
|
t->torrent_ptr->get_handle()
|
||||||
, error_msg));
|
, error_msg));
|
||||||
|
@ -202,8 +204,6 @@ namespace detail
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// lock the session to add the new torrent
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
||||||
mutex::scoped_lock l2(m_mutex);
|
mutex::scoped_lock l2(m_mutex);
|
||||||
|
|
||||||
if (m_torrents.empty() || m_torrents.front() != t)
|
if (m_torrents.empty() || m_torrents.front() != t)
|
||||||
|
@ -328,7 +328,7 @@ namespace detail
|
||||||
boost::tie(finished, progress) = processing->torrent_ptr->check_files();
|
boost::tie(finished, progress) = processing->torrent_ptr->check_files();
|
||||||
|
|
||||||
{
|
{
|
||||||
mutex::scoped_lock l(m_mutex);
|
mutex::scoped_lock l2(m_mutex);
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
@ -340,9 +340,9 @@ namespace detail
|
||||||
m_processing.pop_front();
|
m_processing.pop_front();
|
||||||
|
|
||||||
// make sure the lock order is correct
|
// make sure the lock order is correct
|
||||||
l.unlock();
|
l2.unlock();
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
l.lock();
|
l2.lock();
|
||||||
processing->torrent_ptr->abort();
|
processing->torrent_ptr->abort();
|
||||||
|
|
||||||
processing.reset();
|
processing.reset();
|
||||||
|
@ -481,7 +481,7 @@ namespace detail
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void checker_impl::remove_torrent(sha1_hash const& info_hash)
|
void checker_impl::remove_torrent(sha1_hash const& info_hash, int options)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
||||||
|
@ -490,6 +490,8 @@ namespace detail
|
||||||
if ((*i)->info_hash == info_hash)
|
if ((*i)->info_hash == info_hash)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT((*i)->processing == false);
|
TORRENT_ASSERT((*i)->processing == false);
|
||||||
|
if (options & session::delete_files)
|
||||||
|
(*i)->torrent_ptr->delete_files();
|
||||||
m_torrents.erase(i);
|
m_torrents.erase(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -500,6 +502,8 @@ namespace detail
|
||||||
if ((*i)->info_hash == info_hash)
|
if ((*i)->info_hash == info_hash)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT((*i)->processing == false);
|
TORRENT_ASSERT((*i)->processing == false);
|
||||||
|
if (options & session::delete_files)
|
||||||
|
(*i)->torrent_ptr->delete_files();
|
||||||
m_processing.erase(i);
|
m_processing.erase(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -565,8 +569,19 @@ namespace detail
|
||||||
, m_checker_impl(*this)
|
, m_checker_impl(*this)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// windows XP has a limit of 10 simultaneous connections
|
// windows XP has a limit on the number of
|
||||||
|
// simultaneous half-open TCP connections
|
||||||
|
DWORD windows_version = ::GetVersion();
|
||||||
|
if ((windows_version & 0xff) >= 6)
|
||||||
|
{
|
||||||
|
// on vista the limit is 5 (in home edition)
|
||||||
|
m_half_open.limit(4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// on XP SP2 it's 10
|
||||||
m_half_open.limit(8);
|
m_half_open.limit(8);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_bandwidth_manager[peer_connection::download_channel] = &m_download_channel;
|
m_bandwidth_manager[peer_connection::download_channel] = &m_download_channel;
|
||||||
|
@ -1623,7 +1638,7 @@ namespace detail
|
||||||
boost::intrusive_ptr<torrent_info> ti
|
boost::intrusive_ptr<torrent_info> ti
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const& resume_data
|
, entry const& resume_data
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused
|
, bool paused
|
||||||
, void* userdata)
|
, void* userdata)
|
||||||
|
@ -1655,7 +1670,7 @@ namespace detail
|
||||||
// the thread
|
// the thread
|
||||||
boost::shared_ptr<torrent> torrent_ptr(
|
boost::shared_ptr<torrent> torrent_ptr(
|
||||||
new torrent(*this, m_checker_impl, ti, save_path
|
new torrent(*this, m_checker_impl, ti, save_path
|
||||||
, m_listen_interface, compact_mode, 16 * 1024
|
, m_listen_interface, storage_mode, 16 * 1024
|
||||||
, sc, paused));
|
, sc, paused));
|
||||||
torrent_ptr->start();
|
torrent_ptr->start();
|
||||||
|
|
||||||
|
@ -1701,7 +1716,7 @@ namespace detail
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const&
|
, entry const&
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused
|
, bool paused
|
||||||
, void* userdata)
|
, void* userdata)
|
||||||
|
@ -1735,7 +1750,7 @@ namespace detail
|
||||||
// the thread
|
// the thread
|
||||||
boost::shared_ptr<torrent> torrent_ptr(
|
boost::shared_ptr<torrent> torrent_ptr(
|
||||||
new torrent(*this, m_checker_impl, tracker_url, info_hash, name
|
new torrent(*this, m_checker_impl, tracker_url, info_hash, name
|
||||||
, save_path, m_listen_interface, compact_mode, 16 * 1024
|
, save_path, m_listen_interface, storage_mode, 16 * 1024
|
||||||
, sc, paused));
|
, sc, paused));
|
||||||
torrent_ptr->start();
|
torrent_ptr->start();
|
||||||
|
|
||||||
|
@ -1754,7 +1769,7 @@ namespace detail
|
||||||
return torrent_handle(this, &m_checker_impl, info_hash);
|
return torrent_handle(this, &m_checker_impl, info_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::remove_torrent(const torrent_handle& h)
|
void session_impl::remove_torrent(const torrent_handle& h, int options)
|
||||||
{
|
{
|
||||||
if (h.m_ses != this) return;
|
if (h.m_ses != this) return;
|
||||||
TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0);
|
TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0);
|
||||||
|
@ -1769,6 +1784,8 @@ namespace detail
|
||||||
if (i != m_torrents.end())
|
if (i != m_torrents.end())
|
||||||
{
|
{
|
||||||
torrent& t = *i->second;
|
torrent& t = *i->second;
|
||||||
|
if (options & session::delete_files)
|
||||||
|
t.delete_files();
|
||||||
t.abort();
|
t.abort();
|
||||||
|
|
||||||
if ((!t.is_paused() || t.should_request())
|
if ((!t.is_paused() || t.should_request())
|
||||||
|
@ -1815,7 +1832,7 @@ namespace detail
|
||||||
if (d != 0)
|
if (d != 0)
|
||||||
{
|
{
|
||||||
if (d->processing) d->abort = true;
|
if (d->processing) d->abort = true;
|
||||||
else m_checker_impl.remove_torrent(h.m_info_hash);
|
else m_checker_impl.remove_torrent(h.m_info_hash, options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,6 +361,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
void release_files();
|
void release_files();
|
||||||
|
void delete_files();
|
||||||
void initialize(bool allocate_files);
|
void initialize(bool allocate_files);
|
||||||
bool move_storage(fs::path save_path);
|
bool move_storage(fs::path save_path);
|
||||||
size_type read(char* buf, int slot, int offset, int size);
|
size_type read(char* buf, int slot, int offset, int size);
|
||||||
|
@ -447,7 +448,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the file is empty, just create it. But also make sure
|
// if the file is empty, just create it. But also make sure
|
||||||
// the directory exits.
|
// the directory exists.
|
||||||
if (file_iter->size == 0)
|
if (file_iter->size == 0)
|
||||||
{
|
{
|
||||||
file(m_save_path / file_iter->path, file::out);
|
file(m_save_path / file_iter->path, file::out);
|
||||||
|
@ -470,6 +471,38 @@ namespace libtorrent
|
||||||
std::vector<char>().swap(m_scratch_buffer);
|
std::vector<char>().swap(m_scratch_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void storage::delete_files()
|
||||||
|
{
|
||||||
|
// make sure we don't have the files open
|
||||||
|
m_files.release(this);
|
||||||
|
std::vector<char>().swap(m_scratch_buffer);
|
||||||
|
|
||||||
|
// delete the files from disk
|
||||||
|
std::set<std::string> directories;
|
||||||
|
typedef std::set<std::string>::iterator iter_t;
|
||||||
|
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||||
|
, end(m_info->end_files(true)); i != end; ++i)
|
||||||
|
{
|
||||||
|
std::string p = (m_save_path / i->path).string();
|
||||||
|
fs::path bp = i->path.branch_path();
|
||||||
|
std::pair<iter_t, bool> ret = directories.insert(bp.string());
|
||||||
|
while (ret.second && !bp.empty())
|
||||||
|
{
|
||||||
|
bp = bp.branch_path();
|
||||||
|
std::pair<iter_t, bool> ret = directories.insert(bp.string());
|
||||||
|
}
|
||||||
|
std::remove(p.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the directories. Reverse order to delete
|
||||||
|
// subdirectories first
|
||||||
|
std::for_each(directories.rbegin(), directories.rend()
|
||||||
|
, bind((int(*)(char const*))&std::remove, bind(&std::string::c_str, _1)));
|
||||||
|
|
||||||
|
std::string p = (m_save_path / m_info->name()).string();
|
||||||
|
std::remove(p.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void storage::write_resume_data(entry& rd) const
|
void storage::write_resume_data(entry& rd) const
|
||||||
{
|
{
|
||||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||||
|
@ -931,107 +964,6 @@ namespace libtorrent
|
||||||
return new storage(ti, path, fp);
|
return new storage(ti, path, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supports_sparse_files(fs::path const& p)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(p.is_complete());
|
|
||||||
#if defined(_WIN32)
|
|
||||||
// assume windows API is available
|
|
||||||
DWORD max_component_len = 0;
|
|
||||||
DWORD volume_flags = 0;
|
|
||||||
std::string root_device = p.root_name() + "\\";
|
|
||||||
#if defined(UNICODE)
|
|
||||||
std::wstring wph(safe_convert(root_device));
|
|
||||||
bool ret = ::GetVolumeInformation(wph.c_str(), 0
|
|
||||||
, 0, 0, &max_component_len, &volume_flags, 0, 0);
|
|
||||||
#else
|
|
||||||
bool ret = ::GetVolumeInformation(root_device.c_str(), 0
|
|
||||||
, 0, 0, &max_component_len, &volume_flags, 0, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!ret) return false;
|
|
||||||
if (volume_flags & FILE_SUPPORTS_SPARSE_FILES)
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__)
|
|
||||||
// find the last existing directory of the save path
|
|
||||||
fs::path query_path = p;
|
|
||||||
while (!query_path.empty() && !exists(query_path))
|
|
||||||
query_path = query_path.branch_path();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
|
|
||||||
struct statfs fsinfo;
|
|
||||||
int ret = statfs(query_path.native_directory_string().c_str(), &fsinfo);
|
|
||||||
if (ret != 0) return false;
|
|
||||||
|
|
||||||
attrlist request;
|
|
||||||
request.bitmapcount = ATTR_BIT_MAP_COUNT;
|
|
||||||
request.reserved = 0;
|
|
||||||
request.commonattr = 0;
|
|
||||||
request.volattr = ATTR_VOL_CAPABILITIES;
|
|
||||||
request.dirattr = 0;
|
|
||||||
request.fileattr = 0;
|
|
||||||
request.forkattr = 0;
|
|
||||||
|
|
||||||
struct vol_capabilities_attr_buf
|
|
||||||
{
|
|
||||||
unsigned long length;
|
|
||||||
vol_capabilities_attr_t info;
|
|
||||||
} vol_cap;
|
|
||||||
|
|
||||||
ret = getattrlist(fsinfo.f_mntonname, &request, &vol_cap
|
|
||||||
, sizeof(vol_cap), 0);
|
|
||||||
if (ret != 0) return false;
|
|
||||||
|
|
||||||
if (vol_cap.info.capabilities[VOL_CAPABILITIES_FORMAT]
|
|
||||||
& (VOL_CAP_FMT_SPARSE_FILES | VOL_CAP_FMT_ZERO_RUNS))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// workaround for bugs in Mac OS X where zero run is not reported
|
|
||||||
if (!strcmp(fsinfo.f_fstypename, "hfs")
|
|
||||||
|| !strcmp(fsinfo.f_fstypename, "ufs"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
|
||||||
struct statfs buf;
|
|
||||||
int err = statfs(query_path.native_directory_string().c_str(), &buf);
|
|
||||||
if (err == 0)
|
|
||||||
{
|
|
||||||
switch (buf.f_type)
|
|
||||||
{
|
|
||||||
case 0x5346544e: // NTFS
|
|
||||||
case 0xEF51: // EXT2 OLD
|
|
||||||
case 0xEF53: // EXT2 and EXT3
|
|
||||||
case 0x00011954: // UFS
|
|
||||||
case 0x52654973: // ReiserFS
|
|
||||||
case 0x52345362: // Reiser4
|
|
||||||
case 0x58465342: // XFS
|
|
||||||
case 0x65735546: // NTFS-3G
|
|
||||||
case 0x19540119: // UFS2
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef NDEBUG
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << "statfs returned " << err << std::endl;
|
|
||||||
std::cerr << "errno: " << errno << std::endl;
|
|
||||||
std::cerr << "path: " << query_path.native_directory_string() << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: POSIX implementation
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- piece_manager -----------------------------------------------------
|
// -- piece_manager -----------------------------------------------------
|
||||||
|
|
||||||
piece_manager::piece_manager(
|
piece_manager::piece_manager(
|
||||||
|
@ -1042,15 +974,16 @@ namespace libtorrent
|
||||||
, disk_io_thread& io
|
, disk_io_thread& io
|
||||||
, storage_constructor_type sc)
|
, storage_constructor_type sc)
|
||||||
: m_storage(sc(ti, save_path, fp))
|
: m_storage(sc(ti, save_path, fp))
|
||||||
, m_compact_mode(false)
|
, m_storage_mode(storage_mode_sparse)
|
||||||
, m_fill_mode(true)
|
|
||||||
, m_info(ti)
|
, m_info(ti)
|
||||||
, m_save_path(complete(save_path))
|
, m_save_path(complete(save_path))
|
||||||
|
, m_current_slot(0)
|
||||||
|
, m_out_of_place(false)
|
||||||
|
, m_scratch_piece(-1)
|
||||||
, m_storage_constructor(sc)
|
, m_storage_constructor(sc)
|
||||||
, m_io_thread(io)
|
, m_io_thread(io)
|
||||||
, m_torrent(torrent)
|
, m_torrent(torrent)
|
||||||
{
|
{
|
||||||
m_fill_mode = !supports_sparse_files(save_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piece_manager::~piece_manager()
|
piece_manager::~piece_manager()
|
||||||
|
@ -1081,6 +1014,15 @@ namespace libtorrent
|
||||||
m_io_thread.add_job(j, handler);
|
m_io_thread.add_job(j, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_manager::async_delete_files(
|
||||||
|
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||||
|
{
|
||||||
|
disk_io_job j;
|
||||||
|
j.storage = this;
|
||||||
|
j.action = disk_io_job::delete_files;
|
||||||
|
m_io_thread.add_job(j, handler);
|
||||||
|
}
|
||||||
|
|
||||||
void piece_manager::async_move_storage(fs::path const& p
|
void piece_manager::async_move_storage(fs::path const& p
|
||||||
, boost::function<void(int, disk_io_job const&)> const& handler)
|
, boost::function<void(int, disk_io_job const&)> const& handler)
|
||||||
{
|
{
|
||||||
|
@ -1158,16 +1100,11 @@ namespace libtorrent
|
||||||
m_piece_hasher.erase(i);
|
m_piece_hasher.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot = m_piece_to_slot[piece];
|
int slot = slot_for(piece);
|
||||||
TORRENT_ASSERT(slot != has_no_slot);
|
TORRENT_ASSERT(slot != has_no_slot);
|
||||||
return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece));
|
return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece));
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_manager::release_files_impl()
|
|
||||||
{
|
|
||||||
m_storage->release_files();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool piece_manager::move_storage_impl(fs::path const& save_path)
|
bool piece_manager::move_storage_impl(fs::path const& save_path)
|
||||||
{
|
{
|
||||||
if (m_storage->move_storage(save_path))
|
if (m_storage->move_storage(save_path))
|
||||||
|
@ -1177,26 +1114,39 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_manager::export_piece_map(
|
void piece_manager::export_piece_map(
|
||||||
std::vector<int>& p) const
|
std::vector<int>& p, std::vector<bool> const& have) const
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
{
|
||||||
p.clear();
|
p.clear();
|
||||||
|
p.reserve(m_info->num_pieces());
|
||||||
std::vector<int>::const_reverse_iterator last;
|
std::vector<int>::const_reverse_iterator last;
|
||||||
for (last = m_slot_to_piece.rbegin();
|
for (last = m_slot_to_piece.rbegin();
|
||||||
last != m_slot_to_piece.rend(); ++last)
|
last != m_slot_to_piece.rend(); ++last)
|
||||||
{
|
{
|
||||||
if (*last != unallocated) break;
|
if (*last != unallocated && have[*last]) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<int>::const_iterator i =
|
for (std::vector<int>::const_iterator i =
|
||||||
m_slot_to_piece.begin();
|
m_slot_to_piece.begin();
|
||||||
i != last.base(); ++i)
|
i != last.base(); ++i)
|
||||||
{
|
{
|
||||||
p.push_back(*i);
|
p.push_back(have[*i] ? *i : unassigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.reserve(m_info->num_pieces());
|
||||||
|
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||||
|
{
|
||||||
|
p.push_back(have[i] ? i : unassigned);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1206,11 +1156,10 @@ namespace libtorrent
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (m_storage_mode != storage_mode_compact) return;
|
||||||
|
|
||||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size());
|
TORRENT_ASSERT(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size());
|
||||||
TORRENT_ASSERT(m_piece_to_slot[piece_index] >= 0);
|
|
||||||
|
|
||||||
int slot_index = m_piece_to_slot[piece_index];
|
int slot_index = m_piece_to_slot[piece_index];
|
||||||
|
|
||||||
TORRENT_ASSERT(slot_index >= 0);
|
TORRENT_ASSERT(slot_index >= 0);
|
||||||
|
|
||||||
m_slot_to_piece[slot_index] = unassigned;
|
m_slot_to_piece[slot_index] = unassigned;
|
||||||
|
@ -1218,12 +1167,6 @@ namespace libtorrent
|
||||||
m_free_slots.push_back(slot_index);
|
m_free_slots.push_back(slot_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
int piece_manager::slot_for_piece(int piece_index) const
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces());
|
|
||||||
return m_piece_to_slot[piece_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long piece_manager::piece_crc(
|
unsigned long piece_manager::piece_crc(
|
||||||
int slot_index
|
int slot_index
|
||||||
, int block_size
|
, int block_size
|
||||||
|
@ -1275,11 +1218,7 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(buf);
|
TORRENT_ASSERT(buf);
|
||||||
TORRENT_ASSERT(offset >= 0);
|
TORRENT_ASSERT(offset >= 0);
|
||||||
TORRENT_ASSERT(size > 0);
|
TORRENT_ASSERT(size > 0);
|
||||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size());
|
int slot = slot_for(piece_index);
|
||||||
TORRENT_ASSERT(m_piece_to_slot[piece_index] >= 0
|
|
||||||
&& m_piece_to_slot[piece_index] < (int)m_slot_to_piece.size());
|
|
||||||
int slot = m_piece_to_slot[piece_index];
|
|
||||||
TORRENT_ASSERT(slot >= 0 && slot < (int)m_slot_to_piece.size());
|
|
||||||
return m_storage->read(buf, slot, offset, size);
|
return m_storage->read(buf, slot, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1292,7 +1231,7 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(buf);
|
TORRENT_ASSERT(buf);
|
||||||
TORRENT_ASSERT(offset >= 0);
|
TORRENT_ASSERT(offset >= 0);
|
||||||
TORRENT_ASSERT(size > 0);
|
TORRENT_ASSERT(size > 0);
|
||||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size());
|
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces());
|
||||||
|
|
||||||
if (offset == 0)
|
if (offset == 0)
|
||||||
{
|
{
|
||||||
|
@ -1317,7 +1256,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot = allocate_slot_for_piece(piece_index);
|
int slot = allocate_slot_for_piece(piece_index);
|
||||||
TORRENT_ASSERT(slot >= 0 && slot < (int)m_slot_to_piece.size());
|
|
||||||
m_storage->write(buf, slot, offset, size);
|
m_storage->write(buf, slot, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1426,6 +1364,7 @@ namespace libtorrent
|
||||||
// that piece as unassigned, since this slot
|
// that piece as unassigned, since this slot
|
||||||
// is the correct place for the piece.
|
// is the correct place for the piece.
|
||||||
m_slot_to_piece[other_slot] = unassigned;
|
m_slot_to_piece[other_slot] = unassigned;
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
m_free_slots.push_back(other_slot);
|
m_free_slots.push_back(other_slot);
|
||||||
}
|
}
|
||||||
TORRENT_ASSERT(m_piece_to_slot[piece_index] != current_slot);
|
TORRENT_ASSERT(m_piece_to_slot[piece_index] != current_slot);
|
||||||
|
@ -1485,7 +1424,8 @@ namespace libtorrent
|
||||||
bool piece_manager::check_fastresume(
|
bool piece_manager::check_fastresume(
|
||||||
aux::piece_checker_data& data
|
aux::piece_checker_data& data
|
||||||
, std::vector<bool>& pieces
|
, std::vector<bool>& pieces
|
||||||
, int& num_pieces, bool compact_mode)
|
, int& num_pieces, storage_mode_t storage_mode
|
||||||
|
, std::string& error_msg)
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
@ -1493,7 +1433,7 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(m_info->piece_length() > 0);
|
TORRENT_ASSERT(m_info->piece_length() > 0);
|
||||||
|
|
||||||
m_compact_mode = compact_mode;
|
m_storage_mode = storage_mode;
|
||||||
|
|
||||||
// This will corrupt the storage
|
// This will corrupt the storage
|
||||||
// use while debugging to find
|
// use while debugging to find
|
||||||
|
@ -1503,8 +1443,12 @@ namespace libtorrent
|
||||||
|
|
||||||
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||||
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||||
m_free_slots.clear();
|
TORRENT_ASSERT(m_free_slots.empty());
|
||||||
m_unallocated_slots.clear();
|
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||||
|
|
||||||
|
// assume no piece is out of place (i.e. in a slot
|
||||||
|
// other than the one it should be in)
|
||||||
|
bool out_of_place = false;
|
||||||
|
|
||||||
pieces.clear();
|
pieces.clear();
|
||||||
pieces.resize(m_info->num_pieces(), false);
|
pieces.resize(m_info->num_pieces(), false);
|
||||||
|
@ -1513,13 +1457,14 @@ namespace libtorrent
|
||||||
// if we have fast-resume info
|
// if we have fast-resume info
|
||||||
// use it instead of doing the actual checking
|
// use it instead of doing the actual checking
|
||||||
if (!data.piece_map.empty()
|
if (!data.piece_map.empty()
|
||||||
&& data.piece_map.size() <= m_slot_to_piece.size())
|
&& int(data.piece_map.size()) <= m_info->num_pieces())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < (int)data.piece_map.size(); ++i)
|
for (int i = 0; i < (int)data.piece_map.size(); ++i)
|
||||||
{
|
{
|
||||||
m_slot_to_piece[i] = data.piece_map[i];
|
m_slot_to_piece[i] = data.piece_map[i];
|
||||||
if (data.piece_map[i] >= 0)
|
if (data.piece_map[i] >= 0)
|
||||||
{
|
{
|
||||||
|
if (data.piece_map[i] != i) out_of_place = true;
|
||||||
m_piece_to_slot[data.piece_map[i]] = i;
|
m_piece_to_slot[data.piece_map[i]] = i;
|
||||||
int found_piece = data.piece_map[i];
|
int found_piece = data.piece_map[i];
|
||||||
|
|
||||||
|
@ -1537,27 +1482,54 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
else if (data.piece_map[i] == unassigned)
|
else if (data.piece_map[i] == unassigned)
|
||||||
{
|
{
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
m_free_slots.push_back(i);
|
m_free_slots.push_back(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(data.piece_map[i] == unallocated);
|
TORRENT_ASSERT(data.piece_map[i] == unallocated);
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
m_unallocated_slots.push_back(i);
|
m_unallocated_slots.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_unallocated_slots.reserve(int(pieces.size() - data.piece_map.size()));
|
if (m_storage_mode == storage_mode_compact)
|
||||||
for (int i = (int)data.piece_map.size(); i < (int)pieces.size(); ++i)
|
{
|
||||||
|
m_unallocated_slots.reserve(int(m_info->num_pieces() - data.piece_map.size()));
|
||||||
|
for (int i = (int)data.piece_map.size(); i < (int)m_info->num_pieces(); ++i)
|
||||||
{
|
{
|
||||||
m_unallocated_slots.push_back(i);
|
m_unallocated_slots.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_unallocated_slots.empty())
|
if (m_unallocated_slots.empty())
|
||||||
m_state = state_create_files;
|
{
|
||||||
else if (m_compact_mode)
|
switch_to_full_mode();
|
||||||
m_state = state_create_files;
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_state = state_allocating;
|
{
|
||||||
|
if (!out_of_place)
|
||||||
|
{
|
||||||
|
// if no piece is out of place
|
||||||
|
// since we're in full allocation mode, we can
|
||||||
|
// forget the piece allocation tables
|
||||||
|
|
||||||
|
std::vector<int>().swap(m_piece_to_slot);
|
||||||
|
std::vector<int>().swap(m_slot_to_piece);
|
||||||
|
m_state = state_create_files;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// in this case we're in full allocation mode, but
|
||||||
|
// we're resuming a compact allocated storage
|
||||||
|
m_state = state_expand_pieces;
|
||||||
|
m_current_slot = 0;
|
||||||
|
error_msg = "pieces needs to be reordered";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = state_create_files;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1572,18 +1544,13 @@ namespace libtorrent
|
||||||
|
|
||||||
| |
|
| |
|
||||||
| v
|
| v
|
||||||
| +------------+
|
| +------------+ +---------------+
|
||||||
| | full_check |
|
| | full_check |-->| expand_pieses |
|
||||||
| +------------+
|
| +------------+ +---------------+
|
||||||
| |
|
| | |
|
||||||
| v
|
| v |
|
||||||
| +------------+
|
| +--------------+ |
|
||||||
|->| allocating |
|
+->| create_files | <------+
|
||||||
| +------------+
|
|
||||||
| |
|
|
||||||
| v
|
|
||||||
| +--------------+
|
|
||||||
|->| create_files |
|
|
||||||
+--------------+
|
+--------------+
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
|
@ -1602,67 +1569,97 @@ namespace libtorrent
|
||||||
std::pair<bool, float> piece_manager::check_files(
|
std::pair<bool, float> piece_manager::check_files(
|
||||||
std::vector<bool>& pieces, int& num_pieces, boost::recursive_mutex& mutex)
|
std::vector<bool>& pieces, int& num_pieces, boost::recursive_mutex& mutex)
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
boost::recursive_mutex::scoped_lock l_(mutex);
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
|
l_.unlock();
|
||||||
if (m_state == state_allocating)
|
#endif
|
||||||
{
|
|
||||||
if (m_compact_mode || m_unallocated_slots.empty())
|
|
||||||
{
|
|
||||||
m_state = state_create_files;
|
|
||||||
return std::make_pair(false, 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int(m_unallocated_slots.size()) == m_info->num_pieces()
|
|
||||||
&& !m_fill_mode)
|
|
||||||
{
|
|
||||||
// if there is not a single file on disk, just
|
|
||||||
// create the files
|
|
||||||
m_state = state_create_files;
|
|
||||||
return std::make_pair(false, 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're not in compact mode, make sure the
|
|
||||||
// pieces are spread out and placed at their
|
|
||||||
// final position.
|
|
||||||
TORRENT_ASSERT(!m_unallocated_slots.empty());
|
|
||||||
|
|
||||||
if (!m_fill_mode)
|
|
||||||
{
|
|
||||||
// if we're not filling the allocation
|
|
||||||
// just make sure we move the current pieces
|
|
||||||
// into place, and just skip all other
|
|
||||||
// allocation
|
|
||||||
// allocate_slots returns true if it had to
|
|
||||||
// move any data
|
|
||||||
allocate_slots(m_unallocated_slots.size(), true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
allocate_slots(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(false, 1.f - (float)m_unallocated_slots.size()
|
|
||||||
/ (float)m_slot_to_piece.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_state == state_create_files)
|
if (m_state == state_create_files)
|
||||||
{
|
{
|
||||||
m_storage->initialize(!m_fill_mode && !m_compact_mode);
|
m_storage->initialize(m_storage_mode == storage_mode_allocate);
|
||||||
|
|
||||||
if (!m_unallocated_slots.empty() && !m_compact_mode)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(!m_fill_mode);
|
|
||||||
std::vector<int>().swap(m_unallocated_slots);
|
|
||||||
std::fill(m_slot_to_piece.begin(), m_slot_to_piece.end(), int(unassigned));
|
|
||||||
m_free_slots.resize(m_info->num_pieces());
|
|
||||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
|
||||||
m_free_slots[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_state = state_finished;
|
m_state = state_finished;
|
||||||
return std::make_pair(true, 1.f);
|
return std::make_pair(true, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_state == state_expand_pieces)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (m_scratch_piece >= 0)
|
||||||
|
{
|
||||||
|
int piece = m_scratch_piece;
|
||||||
|
int other_piece = m_slot_to_piece[piece];
|
||||||
|
m_scratch_piece = -1;
|
||||||
|
|
||||||
|
if (other_piece >= 0)
|
||||||
|
{
|
||||||
|
if (m_scratch_buffer2.empty())
|
||||||
|
m_scratch_buffer2.resize(m_info->piece_length());
|
||||||
|
|
||||||
|
m_storage->read(&m_scratch_buffer2[0], piece, 0, m_info->piece_size(other_piece));
|
||||||
|
m_scratch_piece = other_piece;
|
||||||
|
m_piece_to_slot[other_piece] = unassigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the slot where this piece belongs is
|
||||||
|
// free. Just move the piece there.
|
||||||
|
m_storage->write(&m_scratch_buffer[0], piece, 0, m_info->piece_size(piece));
|
||||||
|
m_piece_to_slot[piece] = piece;
|
||||||
|
m_slot_to_piece[piece] = piece;
|
||||||
|
|
||||||
|
if (other_piece >= 0)
|
||||||
|
m_scratch_buffer.swap(m_scratch_buffer2);
|
||||||
|
|
||||||
|
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_current_slot < m_info->num_pieces()
|
||||||
|
&& (m_slot_to_piece[m_current_slot] == m_current_slot
|
||||||
|
|| m_slot_to_piece[m_current_slot] < 0))
|
||||||
|
{
|
||||||
|
++m_current_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_current_slot == m_info->num_pieces())
|
||||||
|
{
|
||||||
|
m_state = state_create_files;
|
||||||
|
std::vector<char>().swap(m_scratch_buffer);
|
||||||
|
std::vector<char>().swap(m_scratch_buffer2);
|
||||||
|
if (m_storage_mode != storage_mode_compact)
|
||||||
|
{
|
||||||
|
std::vector<int>().swap(m_piece_to_slot);
|
||||||
|
std::vector<int>().swap(m_slot_to_piece);
|
||||||
|
}
|
||||||
|
return std::make_pair(false, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int piece = m_slot_to_piece[m_current_slot];
|
||||||
|
TORRENT_ASSERT(piece >= 0);
|
||||||
|
int other_piece = m_slot_to_piece[piece];
|
||||||
|
if (other_piece >= 0)
|
||||||
|
{
|
||||||
|
// there is another piece in the slot
|
||||||
|
// where this one goes. Store it in the scratch
|
||||||
|
// buffer until next iteration.
|
||||||
|
if (m_scratch_buffer.empty())
|
||||||
|
m_scratch_buffer.resize(m_info->piece_length());
|
||||||
|
|
||||||
|
m_storage->read(&m_scratch_buffer[0], piece, 0, m_info->piece_size(other_piece));
|
||||||
|
m_scratch_piece = other_piece;
|
||||||
|
m_piece_to_slot[other_piece] = unassigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the slot where this piece belongs is
|
||||||
|
// free. Just move the piece there.
|
||||||
|
m_storage->move_slot(m_current_slot, piece);
|
||||||
|
m_piece_to_slot[piece] = piece;
|
||||||
|
m_slot_to_piece[m_current_slot] = unassigned;
|
||||||
|
m_slot_to_piece[piece] = piece;
|
||||||
|
|
||||||
|
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(m_state == state_full_check);
|
TORRENT_ASSERT(m_state == state_full_check);
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
@ -1674,12 +1671,13 @@ namespace libtorrent
|
||||||
// initialization for the full check
|
// initialization for the full check
|
||||||
if (m_hash_to_piece.empty())
|
if (m_hash_to_piece.empty())
|
||||||
{
|
{
|
||||||
m_current_slot = 0;
|
|
||||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||||
{
|
{
|
||||||
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
|
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
|
||||||
}
|
}
|
||||||
|
boost::recursive_mutex::scoped_lock l(mutex);
|
||||||
std::fill(pieces.begin(), pieces.end(), false);
|
std::fill(pieces.begin(), pieces.end(), false);
|
||||||
|
num_pieces = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_piece_data.resize(int(m_info->piece_length()));
|
m_piece_data.resize(int(m_info->piece_length()));
|
||||||
|
@ -1694,6 +1692,10 @@ namespace libtorrent
|
||||||
int piece_index = identify_data(m_piece_data, m_current_slot
|
int piece_index = identify_data(m_piece_data, m_current_slot
|
||||||
, pieces, num_pieces, m_hash_to_piece, mutex);
|
, pieces, num_pieces, m_hash_to_piece, mutex);
|
||||||
|
|
||||||
|
if (piece_index != m_current_slot
|
||||||
|
&& piece_index >= 0)
|
||||||
|
m_out_of_place = true;
|
||||||
|
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
TORRENT_ASSERT(piece_index == unassigned || piece_index >= 0);
|
TORRENT_ASSERT(piece_index == unassigned || piece_index >= 0);
|
||||||
|
|
||||||
|
@ -1745,9 +1747,12 @@ namespace libtorrent
|
||||||
std::vector<int>::iterator i =
|
std::vector<int>::iterator i =
|
||||||
std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
|
std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
|
||||||
TORRENT_ASSERT(i != m_free_slots.end());
|
TORRENT_ASSERT(i != m_free_slots.end());
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
{
|
||||||
m_free_slots.erase(i);
|
m_free_slots.erase(i);
|
||||||
m_free_slots.push_back(m_current_slot);
|
m_free_slots.push_back(m_current_slot);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (other_piece >= 0)
|
if (other_piece >= 0)
|
||||||
m_storage->swap_slots(other_slot, m_current_slot);
|
m_storage->swap_slots(other_slot, m_current_slot);
|
||||||
|
@ -1770,7 +1775,8 @@ namespace libtorrent
|
||||||
m_slot_to_piece[other_slot] = piece_index;
|
m_slot_to_piece[other_slot] = piece_index;
|
||||||
m_piece_to_slot[other_piece] = m_current_slot;
|
m_piece_to_slot[other_piece] = m_current_slot;
|
||||||
|
|
||||||
if (piece_index == unassigned)
|
if (piece_index == unassigned
|
||||||
|
&& m_storage_mode == storage_mode_compact)
|
||||||
m_free_slots.push_back(other_slot);
|
m_free_slots.push_back(other_slot);
|
||||||
|
|
||||||
if (piece_index >= 0)
|
if (piece_index >= 0)
|
||||||
|
@ -1845,9 +1851,12 @@ namespace libtorrent
|
||||||
std::vector<int>::iterator i =
|
std::vector<int>::iterator i =
|
||||||
std::find(m_free_slots.begin(), m_free_slots.end(), slot1);
|
std::find(m_free_slots.begin(), m_free_slots.end(), slot1);
|
||||||
TORRENT_ASSERT(i != m_free_slots.end());
|
TORRENT_ASSERT(i != m_free_slots.end());
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
{
|
||||||
m_free_slots.erase(i);
|
m_free_slots.erase(i);
|
||||||
m_free_slots.push_back(slot2);
|
m_free_slots.push_back(slot2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (piece1 >= 0)
|
if (piece1 >= 0)
|
||||||
{
|
{
|
||||||
|
@ -1873,7 +1882,7 @@ namespace libtorrent
|
||||||
// the slot was identified as piece 'piece_index'
|
// the slot was identified as piece 'piece_index'
|
||||||
if (piece_index != unassigned)
|
if (piece_index != unassigned)
|
||||||
m_piece_to_slot[piece_index] = m_current_slot;
|
m_piece_to_slot[piece_index] = m_current_slot;
|
||||||
else
|
else if (m_storage_mode == storage_mode_compact)
|
||||||
m_free_slots.push_back(m_current_slot);
|
m_free_slots.push_back(m_current_slot);
|
||||||
|
|
||||||
m_slot_to_piece[m_current_slot] = piece_index;
|
m_slot_to_piece[m_current_slot] = piece_index;
|
||||||
|
@ -1899,11 +1908,14 @@ namespace libtorrent
|
||||||
(file_offset - current_offset + m_info->piece_length() - 1)
|
(file_offset - current_offset + m_info->piece_length() - 1)
|
||||||
/ m_info->piece_length());
|
/ m_info->piece_length());
|
||||||
|
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
{
|
||||||
for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i)
|
for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_slot_to_piece[i] == unallocated);
|
TORRENT_ASSERT(m_slot_to_piece[i] == unallocated);
|
||||||
m_unallocated_slots.push_back(i);
|
m_unallocated_slots.push_back(i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// current slot will increase by one at the end of the for-loop too
|
// current slot will increase by one at the end of the for-loop too
|
||||||
m_current_slot += skip_blocks - 1;
|
m_current_slot += skip_blocks - 1;
|
||||||
|
@ -1917,8 +1929,39 @@ namespace libtorrent
|
||||||
// clear the memory we've been using
|
// clear the memory we've been using
|
||||||
std::vector<char>().swap(m_piece_data);
|
std::vector<char>().swap(m_piece_data);
|
||||||
std::multimap<sha1_hash, int>().swap(m_hash_to_piece);
|
std::multimap<sha1_hash, int>().swap(m_hash_to_piece);
|
||||||
m_state = state_allocating;
|
|
||||||
|
if (m_storage_mode != storage_mode_compact)
|
||||||
|
{
|
||||||
|
if (!m_out_of_place)
|
||||||
|
{
|
||||||
|
// if no piece is out of place
|
||||||
|
// since we're in full allocation mode, we can
|
||||||
|
// forget the piece allocation tables
|
||||||
|
|
||||||
|
std::vector<int>().swap(m_piece_to_slot);
|
||||||
|
std::vector<int>().swap(m_slot_to_piece);
|
||||||
|
m_state = state_create_files;
|
||||||
|
return std::make_pair(false, 1.f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// in this case we're in full allocation mode, but
|
||||||
|
// we're resuming a compact allocated storage
|
||||||
|
m_state = state_expand_pieces;
|
||||||
|
m_current_slot = 0;
|
||||||
|
return std::make_pair(false, 0.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_unallocated_slots.empty())
|
||||||
|
{
|
||||||
|
switch_to_full_mode();
|
||||||
|
}
|
||||||
|
m_state = state_create_files;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
boost::recursive_mutex::scoped_lock l(mutex);
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
|
#endif
|
||||||
return std::make_pair(false, 1.f);
|
return std::make_pair(false, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,10 +1970,26 @@ namespace libtorrent
|
||||||
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_manager::switch_to_full_mode()
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_storage_mode == storage_mode_compact);
|
||||||
|
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||||
|
// we have allocated all slots, switch to
|
||||||
|
// full allocation mode in order to free
|
||||||
|
// some unnecessary memory.
|
||||||
|
m_storage_mode = storage_mode_sparse;
|
||||||
|
std::vector<int>().swap(m_unallocated_slots);
|
||||||
|
std::vector<int>().swap(m_free_slots);
|
||||||
|
std::vector<int>().swap(m_piece_to_slot);
|
||||||
|
std::vector<int>().swap(m_slot_to_piece);
|
||||||
|
}
|
||||||
|
|
||||||
int piece_manager::allocate_slot_for_piece(int piece_index)
|
int piece_manager::allocate_slot_for_piece(int piece_index)
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
if (m_storage_mode != storage_mode_compact) return piece_index;
|
||||||
|
|
||||||
// INVARIANT_CHECK;
|
// INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT(piece_index >= 0);
|
TORRENT_ASSERT(piece_index >= 0);
|
||||||
|
@ -2030,25 +2089,26 @@ namespace libtorrent
|
||||||
debug_log();
|
debug_log();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(slot_index >= 0);
|
TORRENT_ASSERT(slot_index >= 0);
|
||||||
TORRENT_ASSERT(slot_index < (int)m_slot_to_piece.size());
|
TORRENT_ASSERT(slot_index < (int)m_slot_to_piece.size());
|
||||||
|
|
||||||
|
if (m_unallocated_slots.empty())
|
||||||
|
{
|
||||||
|
switch_to_full_mode();
|
||||||
|
}
|
||||||
|
|
||||||
return slot_index;
|
return slot_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool piece_manager::allocate_slots(int num_slots, bool abort_on_disk)
|
bool piece_manager::allocate_slots(int num_slots, bool abort_on_disk)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(num_slots > 0);
|
|
||||||
|
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
TORRENT_ASSERT(num_slots > 0);
|
||||||
|
|
||||||
// INVARIANT_CHECK;
|
// INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_unallocated_slots.empty());
|
TORRENT_ASSERT(!m_unallocated_slots.empty());
|
||||||
|
TORRENT_ASSERT(m_storage_mode == storage_mode_compact);
|
||||||
const int stack_buffer_size = 16*1024;
|
|
||||||
char zeroes[stack_buffer_size];
|
|
||||||
memset(zeroes, 0, stack_buffer_size);
|
|
||||||
|
|
||||||
bool written = false;
|
bool written = false;
|
||||||
|
|
||||||
|
@ -2069,32 +2129,57 @@ namespace libtorrent
|
||||||
m_piece_to_slot[pos] = pos;
|
m_piece_to_slot[pos] = pos;
|
||||||
written = true;
|
written = true;
|
||||||
}
|
}
|
||||||
else if (m_fill_mode)
|
|
||||||
{
|
|
||||||
int piece_size = int(m_info->piece_size(pos));
|
|
||||||
int offset = 0;
|
|
||||||
for (; piece_size > 0; piece_size -= stack_buffer_size
|
|
||||||
, offset += stack_buffer_size)
|
|
||||||
{
|
|
||||||
m_storage->write(zeroes, pos, offset
|
|
||||||
, (std::min)(piece_size, stack_buffer_size));
|
|
||||||
}
|
|
||||||
written = true;
|
|
||||||
}
|
|
||||||
m_unallocated_slots.erase(m_unallocated_slots.begin());
|
m_unallocated_slots.erase(m_unallocated_slots.begin());
|
||||||
m_slot_to_piece[new_free_slot] = unassigned;
|
m_slot_to_piece[new_free_slot] = unassigned;
|
||||||
m_free_slots.push_back(new_free_slot);
|
m_free_slots.push_back(new_free_slot);
|
||||||
if (abort_on_disk && written) return true;
|
if (abort_on_disk && written) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(m_free_slots.size() > 0);
|
TORRENT_ASSERT(m_free_slots.size() > 0);
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int piece_manager::slot_for(int piece) const
|
||||||
|
{
|
||||||
|
if (m_storage_mode != storage_mode_compact) return piece;
|
||||||
|
TORRENT_ASSERT(piece < int(m_piece_to_slot.size()));
|
||||||
|
TORRENT_ASSERT(piece >= 0);
|
||||||
|
return m_piece_to_slot[piece];
|
||||||
|
}
|
||||||
|
|
||||||
|
int piece_manager::piece_for(int slot) const
|
||||||
|
{
|
||||||
|
if (m_storage_mode != storage_mode_compact) return slot;
|
||||||
|
TORRENT_ASSERT(slot < int(m_slot_to_piece.size()));
|
||||||
|
TORRENT_ASSERT(slot >= 0);
|
||||||
|
return m_slot_to_piece[slot];
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void piece_manager::check_invariant() const
|
void piece_manager::check_invariant() const
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
if (m_unallocated_slots.empty() && m_state == state_finished)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_storage_mode != storage_mode_compact);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_storage_mode != storage_mode_compact)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||||
|
TORRENT_ASSERT(m_free_slots.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_storage_mode != storage_mode_compact
|
||||||
|
&& m_state != state_expand_pieces
|
||||||
|
&& m_state != state_full_check)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_piece_to_slot.empty());
|
||||||
|
TORRENT_ASSERT(m_slot_to_piece.empty());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (m_piece_to_slot.empty()) return;
|
if (m_piece_to_slot.empty()) return;
|
||||||
|
|
||||||
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces());
|
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces());
|
||||||
|
@ -2200,6 +2285,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_STORAGE_DEBUG
|
#ifdef TORRENT_STORAGE_DEBUG
|
||||||
void piece_manager::debug_log() const
|
void piece_manager::debug_log() const
|
||||||
|
|
|
@ -154,7 +154,7 @@ namespace libtorrent
|
||||||
, boost::intrusive_ptr<torrent_info> tf
|
, boost::intrusive_ptr<torrent_info> tf
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused)
|
, bool paused)
|
||||||
|
@ -195,7 +195,7 @@ namespace libtorrent
|
||||||
, m_total_redundant_bytes(0)
|
, m_total_redundant_bytes(0)
|
||||||
, m_net_interface(net_interface.address(), 0)
|
, m_net_interface(net_interface.address(), 0)
|
||||||
, m_save_path(complete(save_path))
|
, m_save_path(complete(save_path))
|
||||||
, m_compact_mode(compact_mode)
|
, m_storage_mode(storage_mode)
|
||||||
, m_default_block_size(block_size)
|
, m_default_block_size(block_size)
|
||||||
, m_connections_initialized(true)
|
, m_connections_initialized(true)
|
||||||
, m_settings(ses.settings())
|
, m_settings(ses.settings())
|
||||||
|
@ -215,7 +215,7 @@ namespace libtorrent
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, bool compact_mode
|
, storage_mode_t storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused)
|
, bool paused)
|
||||||
|
@ -255,7 +255,7 @@ namespace libtorrent
|
||||||
, m_total_redundant_bytes(0)
|
, m_total_redundant_bytes(0)
|
||||||
, m_net_interface(net_interface.address(), 0)
|
, m_net_interface(net_interface.address(), 0)
|
||||||
, m_save_path(complete(save_path))
|
, m_save_path(complete(save_path))
|
||||||
, m_compact_mode(compact_mode)
|
, m_storage_mode(storage_mode)
|
||||||
, m_default_block_size(block_size)
|
, m_default_block_size(block_size)
|
||||||
, m_connections_initialized(false)
|
, m_connections_initialized(false)
|
||||||
, m_settings(ses.settings())
|
, m_settings(ses.settings())
|
||||||
|
@ -1032,6 +1032,16 @@ namespace libtorrent
|
||||||
m_announce_timer.cancel();
|
m_announce_timer.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent::on_files_deleted(int ret, disk_io_job const& j)
|
||||||
|
{
|
||||||
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
|
||||||
|
if (alerts().should_post(alert::warning))
|
||||||
|
{
|
||||||
|
alerts().post_alert(torrent_deleted_alert(get_handle(), "files deleted"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::on_files_released(int ret, disk_io_job const& j)
|
void torrent::on_files_released(int ret, disk_io_job const& j)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1668,8 +1678,6 @@ namespace libtorrent
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_connections.find(a) == m_connections.end());
|
|
||||||
|
|
||||||
// add the newly connected peer to this torrent's peer list
|
// add the newly connected peer to this torrent's peer list
|
||||||
TORRENT_ASSERT(m_connections.find(a) == m_connections.end());
|
TORRENT_ASSERT(m_connections.find(a) == m_connections.end());
|
||||||
m_connections.insert(
|
m_connections.insert(
|
||||||
|
@ -1883,10 +1891,13 @@ namespace libtorrent
|
||||||
std::make_pair(a, boost::get_pointer(c)));
|
std::make_pair(a, boost::get_pointer(c)));
|
||||||
m_ses.m_connections.insert(std::make_pair(s, c));
|
m_ses.m_connections.insert(std::make_pair(s, c));
|
||||||
|
|
||||||
|
int timeout = settings().peer_connect_timeout;
|
||||||
|
if (peerinfo) timeout += 3 * peerinfo->failcount;
|
||||||
|
|
||||||
m_ses.m_half_open.enqueue(
|
m_ses.m_half_open.enqueue(
|
||||||
bind(&peer_connection::connect, c, _1)
|
bind(&peer_connection::connect, c, _1)
|
||||||
, bind(&peer_connection::timed_out, c)
|
, bind(&peer_connection::timed_out, c)
|
||||||
, seconds(settings().peer_connect_timeout));
|
, seconds(timeout));
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -2215,10 +2226,22 @@ namespace libtorrent
|
||||||
bool done = true;
|
bool done = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
std::string error_msg;
|
||||||
TORRENT_ASSERT(m_storage);
|
TORRENT_ASSERT(m_storage);
|
||||||
TORRENT_ASSERT(m_owning_storage.get());
|
TORRENT_ASSERT(m_owning_storage.get());
|
||||||
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
|
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
|
||||||
, m_compact_mode);
|
, m_storage_mode, error_msg);
|
||||||
|
|
||||||
|
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
|
||||||
|
{
|
||||||
|
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
|
||||||
|
get_handle(), error_msg));
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
(*m_ses.m_logger) << "fastresume data for "
|
||||||
|
<< torrent_file().name() << " rejected: "
|
||||||
|
<< error_msg << "\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -2378,8 +2401,6 @@ namespace libtorrent
|
||||||
|
|
||||||
piece_manager& torrent::filesystem()
|
piece_manager& torrent::filesystem()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(m_owning_storage.get());
|
TORRENT_ASSERT(m_owning_storage.get());
|
||||||
return *m_owning_storage;
|
return *m_owning_storage;
|
||||||
}
|
}
|
||||||
|
@ -2537,6 +2558,29 @@ namespace libtorrent
|
||||||
return limit;
|
return limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent::delete_files()
|
||||||
|
{
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||||
|
for (peer_iterator i = m_connections.begin();
|
||||||
|
i != m_connections.end(); ++i)
|
||||||
|
{
|
||||||
|
(*i->second->m_logger) << "*** DELETING FILES IN TORRENT\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
disconnect_all();
|
||||||
|
m_paused = true;
|
||||||
|
// tell the tracker that we stopped
|
||||||
|
m_event = tracker_request::stopped;
|
||||||
|
|
||||||
|
if (m_owning_storage.get())
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_storage);
|
||||||
|
m_storage->async_delete_files(
|
||||||
|
bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::pause()
|
void torrent::pause()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -2768,7 +2812,7 @@ namespace libtorrent
|
||||||
!boost::bind(&peer_connection::is_connecting
|
!boost::bind(&peer_connection::is_connecting
|
||||||
, boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
|
, boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
|
||||||
|
|
||||||
st.compact_mode = m_compact_mode;
|
st.storage_mode = m_storage_mode;
|
||||||
|
|
||||||
st.num_complete = m_complete;
|
st.num_complete = m_complete;
|
||||||
st.num_incomplete = m_incomplete;
|
st.num_incomplete = m_incomplete;
|
||||||
|
|
|
@ -661,7 +661,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!t->valid_metadata()) return entry();
|
if (!t->valid_metadata()) return entry();
|
||||||
|
|
||||||
t->filesystem().export_piece_map(piece_index);
|
std::vector<bool> have_pieces = t->pieces();
|
||||||
|
|
||||||
entry ret(entry::dictionary_t);
|
entry ret(entry::dictionary_t);
|
||||||
|
|
||||||
|
@ -673,10 +673,6 @@ namespace libtorrent
|
||||||
const sha1_hash& info_hash = t->torrent_file().info_hash();
|
const sha1_hash& info_hash = t->torrent_file().info_hash();
|
||||||
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
||||||
|
|
||||||
ret["slots"] = entry(entry::list_t);
|
|
||||||
entry::list_type& slots = ret["slots"].list();
|
|
||||||
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
|
|
||||||
|
|
||||||
// blocks per piece
|
// blocks per piece
|
||||||
int num_blocks_per_piece =
|
int num_blocks_per_piece =
|
||||||
static_cast<int>(t->torrent_file().piece_length()) / t->block_size();
|
static_cast<int>(t->torrent_file().piece_length()) / t->block_size();
|
||||||
|
@ -706,6 +702,8 @@ namespace libtorrent
|
||||||
// the unfinished piece's index
|
// the unfinished piece's index
|
||||||
piece_struct["piece"] = i->index;
|
piece_struct["piece"] = i->index;
|
||||||
|
|
||||||
|
have_pieces[i->index] = true;
|
||||||
|
|
||||||
std::string bitmask;
|
std::string bitmask;
|
||||||
const int num_bitmask_bytes
|
const int num_bitmask_bytes
|
||||||
= (std::max)(num_blocks_per_piece / 8, 1);
|
= (std::max)(num_blocks_per_piece / 8, 1);
|
||||||
|
@ -722,10 +720,10 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
piece_struct["bitmask"] = bitmask;
|
piece_struct["bitmask"] = bitmask;
|
||||||
|
|
||||||
TORRENT_ASSERT(t->filesystem().slot_for_piece(i->index) >= 0);
|
TORRENT_ASSERT(t->filesystem().slot_for(i->index) >= 0);
|
||||||
unsigned long adler
|
unsigned long adler
|
||||||
= t->filesystem().piece_crc(
|
= t->filesystem().piece_crc(
|
||||||
t->filesystem().slot_for_piece(i->index)
|
t->filesystem().slot_for(i->index)
|
||||||
, t->block_size()
|
, t->block_size()
|
||||||
, i->info);
|
, i->info);
|
||||||
|
|
||||||
|
@ -735,6 +733,11 @@ namespace libtorrent
|
||||||
up.push_back(piece_struct);
|
up.push_back(piece_struct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t->filesystem().export_piece_map(piece_index, have_pieces);
|
||||||
|
entry::list_type& slots = ret["slots"].list();
|
||||||
|
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
|
||||||
|
|
||||||
// write local peers
|
// write local peers
|
||||||
|
|
||||||
entry::list_type& peer_list = ret["peers"].list();
|
entry::list_type& peer_list = ret["peers"].list();
|
||||||
|
|
Loading…
Reference in New Issue