diff --git a/docs/manual.rst b/docs/manual.rst index e6f788ad9..1c7184688 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -1307,7 +1307,7 @@ Its declaration looks like this:: bool has_metadata() const; boost::filesystem::path save_path() const; - bool move_storage(boost::filesystem::path const& save_path) const; + void move_storage(boost::filesystem::path const& save_path) const; sha1_hash info_hash() const; @@ -1404,14 +1404,13 @@ move_storage() :: - bool move_storage(boost::filesystem::path const& save_path) const; + void move_storage(boost::filesystem::path const& save_path) const; Moves the file(s) that this torrent are currently seeding from or downloading to. This operation will only have the desired effect if the given ``save_path`` is located on -the same drive as the original save path. If the move operation fails, this function -returns false, otherwise true. Post condition for successful operation is: -``save_path() == save_path``. - +the same drive as the original save path. Since disk IO is performed in a separate +thread, this operation is also asynchronous. Once the operation completes, the +``storage_moved_alert`` is generated, with the new path as the message. force_reannounce() ------------------ @@ -1677,7 +1676,9 @@ There are three cases where this function will just return an empty ``entry``: Note that by the time this function returns, the resume data may already be invalid if the torrent is still downloading! The recommended practice is to first pause the torrent, then generate the -fast resume data, and then close it down. +fast resume data, and then close it down. Since the disk IO is done in a separate thread, in order +to synchronize, you shoule to wait for the ``torrent_paused_alert`` before you write the resume +data. It is still a good idea to save resume data periodically during download as well as when closing down. In full allocation mode the reume data is never invalidated by subsequent @@ -3240,6 +3241,36 @@ This alert is generated when a peer is blocked by the IP filter. It has the seve virtual std::auto_ptr clone() const; }; +storage_moved_alert +------------------- + +The ``storage_moved_alert`` is generated when all the disk IO has completed and the +files have been moved, as an effect of a call to ``torrent_handle::move_storage``. This +is useful to synchronize with the actual disk. + +:: + + struct storage_moved_alert: torrent_alert + { + storage_moved_alert(torrent_handle const& h, std::string const& path); + virtual std::auto_ptr clone() const; + }; + +torrent_paused_alert +-------------------- + +This alert is generated as a response to a ``torrent_handle::pause`` request. It is +generated once all disk IO is complete and the files in the torrent have been closed. +This is useful for synchronizing with the disk. + +:: + + struct torrent_paused_alert: torrent_alert + { + torrent_paused_alert(torrent_handle const& h, std::string const& msg); + virtual std::auto_ptr clone() const; + }; + dispatcher ---------- diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index e3e23ad05..7b32d2502 100755 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -81,8 +81,6 @@ namespace libtorrent { return std::auto_ptr(new tracker_warning_alert(*this)); } }; - - struct TORRENT_EXPORT tracker_reply_alert: torrent_alert { tracker_reply_alert(torrent_handle const& h @@ -186,6 +184,26 @@ namespace libtorrent { return std::auto_ptr(new torrent_finished_alert(*this)); } }; + struct TORRENT_EXPORT storage_moved_alert: torrent_alert + { + storage_moved_alert(torrent_handle const& h, std::string const& path) + : torrent_alert(h, alert::warning, path) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new storage_moved_alert(*this)); } + }; + + struct TORRENT_EXPORT torrent_paused_alert: torrent_alert + { + torrent_paused_alert(torrent_handle const& h, std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new torrent_paused_alert(*this)); } + }; + struct TORRENT_EXPORT url_seed_alert: torrent_alert { url_seed_alert( diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 70b64d8f8..552b6e89f 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -210,8 +210,10 @@ namespace libtorrent fs::path save_path() const; - void async_release_files(); - void async_move_storage(fs::path const& p); + void async_release_files( + boost::function const& handler); + void async_move_storage(fs::path const& p + , boost::function const& handler); // fills the vector that maps all allocated // slots to the piece that is stored (or diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 0ff2f5221..9cc4784f2 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -526,6 +526,9 @@ namespace libtorrent private: + void on_files_released(int ret, disk_io_job const& j); + void on_storage_moved(int ret, disk_io_job const& j); + void on_piece_verified(int ret, disk_io_job const& j , boost::function f); diff --git a/src/storage.cpp b/src/storage.cpp index e4765989f..f0f2241c0 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1090,21 +1090,23 @@ namespace libtorrent return m_storage->verify_resume_data(rd, error); } - void piece_manager::async_release_files() + void piece_manager::async_release_files( + boost::function const& handler) { disk_io_job j; j.storage = this; j.action = disk_io_job::release_files; - m_io_thread.add_job(j); + 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 const& handler) { disk_io_job j; j.storage = this; j.action = disk_io_job::move_storage; j.str = p.string(); - m_io_thread.add_job(j); + m_io_thread.add_job(j, handler); } void piece_manager::async_read( diff --git a/src/torrent.cpp b/src/torrent.cpp index e4589392f..d2f4eaac8 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1007,10 +1007,21 @@ namespace libtorrent // disconnect all peers and close all // files belonging to the torrents disconnect_all(); - if (m_owning_storage.get()) m_storage->async_release_files(); + if (m_owning_storage.get()) m_storage->async_release_files( + bind(&torrent::on_files_released, shared_from_this(), _1, _2)); m_owning_storage = 0; } + void torrent::on_files_released(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_paused_alert(get_handle(), "torrent paused")); + } + } + void torrent::announce_piece(int index) { // INVARIANT_CHECK; @@ -2030,7 +2041,8 @@ namespace libtorrent , bind(&peer_connection::disconnect, _1)); assert(m_storage); - m_storage->async_release_files(); + m_storage->async_release_files( + bind(&torrent::on_files_released, shared_from_this(), _1, _2)); } // called when torrent is complete (all pieces downloaded) @@ -2259,7 +2271,8 @@ namespace libtorrent if (m_owning_storage.get()) { - m_owning_storage->async_move_storage(save_path); + m_owning_storage->async_move_storage(save_path + , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2)); } else { @@ -2267,6 +2280,16 @@ namespace libtorrent } } + void torrent::on_storage_moved(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(storage_moved_alert(get_handle(), j.str)); + } + } + piece_manager& torrent::filesystem() { INVARIANT_CHECK; @@ -2434,7 +2457,8 @@ namespace libtorrent assert(m_storage); // TOOD: add a callback which posts // an alert for the client to sync. with - m_storage->async_release_files(); + m_storage->async_release_files( + bind(&torrent::on_files_released, shared_from_this(), _1, _2)); } } diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 0471f7cbd..447017af6 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -103,12 +103,14 @@ void run_storage_tests(torrent_info& info, bool compact_allocation = true) TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end() , true)); + + boost::function none; TEST_CHECK(exists("temp_storage")); - pm->async_move_storage("temp_storage2"); + pm->async_move_storage("temp_storage2", none); test_sleep(2000); TEST_CHECK(!exists("temp_storage")); TEST_CHECK(exists("temp_storage2/temp_storage")); - pm->async_move_storage("."); + pm->async_move_storage(".", none); test_sleep(2000); TEST_CHECK(!exists("temp_storage2/temp_storage")); remove_all("temp_storage2"); @@ -122,7 +124,7 @@ void run_storage_tests(torrent_info& info, bool compact_allocation = true) pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, piece_size)); r.piece = 2; pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size)); - pm->async_release_files(); + pm->async_release_files(none); } }