From fc9dabe1ab954c80d4c4072063545e3f87308d98 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 20 Nov 2016 23:58:48 -0500 Subject: [PATCH] start chipping away at removing disk_io_job from the disk_interface --- include/libtorrent/disk_interface.hpp | 8 +-- include/libtorrent/disk_io_job.hpp | 17 ++++- include/libtorrent/disk_io_thread.hpp | 8 +-- include/libtorrent/peer_connection.hpp | 8 ++- include/libtorrent/torrent.hpp | 13 ++-- src/create_torrent.cpp | 52 +++++++------- src/disk_io_job.cpp | 39 +++++++++++ src/disk_io_thread.cpp | 16 ++--- src/peer_connection.cpp | 91 ++++++++++++------------- src/smart_ban.cpp | 28 +++++--- src/torrent.cpp | 93 ++++++++++++++------------ 11 files changed, 222 insertions(+), 151 deletions(-) diff --git a/include/libtorrent/disk_interface.hpp b/include/libtorrent/disk_interface.hpp index d7c121e77..b290ee8f7 100644 --- a/include/libtorrent/disk_interface.hpp +++ b/include/libtorrent/disk_interface.hpp @@ -60,14 +60,14 @@ namespace libtorrent }; virtual void async_read(storage_interface* storage, peer_request const& r - , std::function handler, void* requester - , int flags = 0) = 0; + , std::function handler, void* requester, int flags = 0) = 0; virtual void async_write(storage_interface* storage, peer_request const& r , disk_buffer_holder buffer - , std::function handler + , std::function handler , int flags = 0) = 0; virtual void async_hash(storage_interface* storage, int piece, int flags - , std::function handler, void* requester) = 0; + , std::function handler, void* requester) = 0; virtual void async_move_storage(storage_interface* storage, std::string const& p, int flags , std::function handler) = 0; virtual void async_release_files(storage_interface* storage diff --git a/include/libtorrent/disk_io_job.hpp b/include/libtorrent/disk_io_job.hpp index 26647fd6f..f74d95d55 100644 --- a/include/libtorrent/disk_io_job.hpp +++ b/include/libtorrent/disk_io_job.hpp @@ -35,7 +35,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/error_code.hpp" #include "libtorrent/tailqueue.hpp" +#include "libtorrent/peer_request.hpp" #include "libtorrent/aux_/block_cache_reference.hpp" +#include "libtorrent/sha1_hash.hpp" + +#include "libtorrent/aux_/disable_warnings_push.hpp" +#include +#include "libtorrent/aux_/disable_warnings_pop.hpp" #include #include @@ -68,6 +74,8 @@ namespace libtorrent disk_io_job(disk_io_job const&) = delete; disk_io_job& operator=(disk_io_job const&) = delete; + void call_callback(); + enum action_t { read @@ -144,7 +152,14 @@ namespace libtorrent std::shared_ptr storage; // this is called when operation completes - std::function callback; + + using read_handler = std::function; + using write_handler = std::function; + using hash_handler = std::function; + using generic_handler = std::function; + + boost::variant callback; // the error code from the file operation // on error, this also contains the path of the diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index c2a7812df..502386745 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -292,14 +292,14 @@ namespace libtorrent void abort(bool wait); void async_read(storage_interface* storage, peer_request const& r - , std::function handler, void* requester - , int flags = 0) override; + , std::function handler, void* requester, int flags = 0) override; void async_write(storage_interface* storage, peer_request const& r , disk_buffer_holder buffer - , std::function handler + , std::function handler , int flags = 0) override; void async_hash(storage_interface* storage, int piece, int flags - , std::function handler, void* requester) override; + , std::function handler, void* requester) override; void async_move_storage(storage_interface* storage, std::string const& p, int flags , std::function handler) override; void async_release_files(storage_interface* storage diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 1ad7a0ddb..17e9a75f5 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -760,11 +760,13 @@ namespace libtorrent void do_update_interest(); void fill_send_buffer(); - void on_disk_read_complete(disk_io_job const* j, peer_request r + void on_disk_read_complete(aux::block_cache_reference ref + , char* disk_block, int flags, storage_error const& error, peer_request r , time_point issue_time); - void on_disk_write_complete(disk_io_job const* j + void on_disk_write_complete(storage_error const& error , peer_request r, std::shared_ptr t); - void on_seed_mode_hashed(disk_io_job const* j); + void on_seed_mode_hashed(int status, int piece + , sha1_hash const& piece_hash, storage_error const& error); int request_timeout() const; void check_graceful_pause(); diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 633555a8d..6617ec556 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -353,7 +353,8 @@ namespace libtorrent void on_resume_data_checked(disk_io_job const* j); void on_force_recheck(disk_io_job const* j); - void on_piece_hashed(disk_io_job const* j); + void on_piece_hashed(int status, int piece, sha1_hash const& piece_hash + , storage_error const& error); void files_checked(); void start_checking(); @@ -378,7 +379,7 @@ namespace libtorrent enum flags_t { overwrite_existing = 1 }; void add_piece(int piece, char const* data, int flags = 0); - void on_disk_write_complete(disk_io_job const* j + void on_disk_write_complete(storage_error const& error , peer_request p); void on_disk_tick_done(disk_io_job const* j); @@ -391,8 +392,9 @@ namespace libtorrent error_code error; }; void read_piece(int piece); - void on_disk_read_complete(disk_io_job const* j, peer_request r - , std::shared_ptr rp); + void on_disk_read_complete(aux::block_cache_reference ref + , char* block, int flags, storage_error const& se + , peer_request r, std::shared_ptr rp); storage_mode_t storage_mode() const; storage_interface* get_storage(); @@ -867,7 +869,8 @@ namespace libtorrent void resume_download(); void verify_piece(int piece); - void on_piece_verified(disk_io_job const* j); + void on_piece_verified(int const status, int const piece + , sha1_hash const& piece_hash, storage_error const& error); // this is called whenever a peer in this swarm becomes interesting // it is responsible for issuing a block request, if appropriate diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index a2483fd13..5163e587f 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -158,34 +158,42 @@ namespace libtorrent } } - void on_hash(disk_io_job const* j, create_torrent* t - , std::shared_ptr storage, disk_io_thread* iothread - , int* piece_counter, int* completed_piece - , std::function const* f, error_code* ec) + struct hash_state { - if (j->ret != 0) + create_torrent& ct; + std::shared_ptr storage; + disk_io_thread& iothread; + int piece_counter; + int completed_piece; + std::function const& f; + error_code& ec; + }; + + void on_hash(int const status, int const piece, sha1_hash const& piece_hash + , storage_error const& error, hash_state* st) + { + if (status != 0) { // on error - *ec = j->error.ec; - iothread->abort(true); + st->ec = error.ec; + st->iothread.abort(true); return; } - t->set_hash(j->piece, sha1_hash(j->d.piece_hash)); - (*f)(*completed_piece); - ++(*completed_piece); - if (*piece_counter < t->num_pieces()) + st->ct.set_hash(piece, sha1_hash(piece_hash)); + st->f(st->completed_piece); + ++st->completed_piece; + if (st->piece_counter < st->ct.num_pieces()) { - iothread->async_hash(storage.get(), *piece_counter + st->iothread.async_hash(st->storage.get(), st->piece_counter , disk_io_job::sequential_access - , std::bind(&on_hash, _1, t, storage, iothread - , piece_counter, completed_piece, f, ec), nullptr); - ++(*piece_counter); + , std::bind(&on_hash, _1, _2, _3, _4, st), nullptr); + ++st->piece_counter; } else { - iothread->abort(true); + st->iothread.abort(true); } - iothread->submit_jobs(); + st->iothread.submit_jobs(); } } // anonymous namespace @@ -283,18 +291,16 @@ namespace libtorrent alert_manager dummy2(0, 0); disk_thread.set_settings(&sett, dummy2); - int piece_counter = 0; - int completed_piece = 0; int piece_read_ahead = 15 * 1024 * 1024 / t.piece_length(); if (piece_read_ahead < 1) piece_read_ahead = 1; + hash_state st = { t, storage, disk_thread, 0, 0, f, ec }; for (int i = 0; i < piece_read_ahead; ++i) { disk_thread.async_hash(storage.get(), i, disk_io_job::sequential_access - , std::bind(&on_hash, _1, &t, storage, &disk_thread - , &piece_counter, &completed_piece, &f, &ec), nullptr); - ++piece_counter; - if (piece_counter >= t.num_pieces()) break; + , std::bind(&on_hash, _1, _2, _3, _4, &st), nullptr); + ++st.piece_counter; + if (st.piece_counter >= t.num_pieces()) break; } disk_thread.submit_jobs(); ios.run(ec); diff --git a/src/disk_io_job.cpp b/src/disk_io_job.cpp index f58c7b1e9..33202eeaa 100644 --- a/src/disk_io_job.cpp +++ b/src/disk_io_job.cpp @@ -35,6 +35,40 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + namespace { + struct caller_visitor : boost::static_visitor<> + { + explicit caller_visitor(disk_io_job& j) : m_job(j) {} + + void operator()(disk_io_job::read_handler& h) const + { + if (!h) return; + h(m_job.d.io.ref, m_job.buffer.disk_block, m_job.flags, m_job.error); + } + + void operator()(disk_io_job::write_handler& h) const + { + if (!h) return; + h(m_job.error); + } + + void operator()(disk_io_job::hash_handler& h) const + { + if (!h) return; + h(m_job.ret, m_job.piece, sha1_hash(m_job.d.piece_hash), m_job.error); + } + + void operator()(disk_io_job::generic_handler& h) const + { + if (!h) return; + h(&m_job); + } + + private: + disk_io_job& m_job; + }; + } + disk_io_job::disk_io_job() : piece(0) , action(read) @@ -53,6 +87,11 @@ namespace libtorrent free(buffer.string); } + void disk_io_job::call_callback() + { + boost::apply_visitor(caller_visitor(*this), callback); + } + bool disk_io_job::completed(cached_piece_entry const* pe, int block_size) { if (action != write) return false; diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 7a1cc087f..3c8cdb930 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1509,8 +1509,8 @@ namespace libtorrent } void disk_io_thread::async_read(storage_interface* storage, peer_request const& r - , std::function handler, void* requester - , int const flags) + , std::function handler, void* requester, int const flags) { TORRENT_ASSERT(r.length <= m_disk_cache.block_size()); TORRENT_ASSERT(r.length <= 16 * 1024); @@ -1534,7 +1534,7 @@ namespace libtorrent switch (ret) { case 0: - if (j->callback) j->callback(j); + j->call_callback(); free_job(j); break; case 1: @@ -1621,7 +1621,7 @@ namespace libtorrent void disk_io_thread::async_write(storage_interface* storage, peer_request const& r , disk_buffer_holder buffer - , std::function handler + , std::function handler , int const flags) { TORRENT_ASSERT(r.length <= m_disk_cache.block_size()); @@ -1723,7 +1723,7 @@ namespace libtorrent } void disk_io_thread::async_hash(storage_interface* storage, int piece, int flags - , std::function handler, void* requester) + , std::function handler, void* requester) { disk_io_job* j = allocate_job(disk_io_job::hash); j->storage = storage->shared_from_this(); @@ -1752,7 +1752,7 @@ namespace libtorrent #endif l.unlock(); - if (j->callback) j->callback(j); + j->call_callback(); free_job(j); return; } @@ -1903,7 +1903,7 @@ namespace libtorrent if (m_abort) { j->error.ec = boost::asio::error::operation_aborted; - if (j->callback) j->callback(j); + j->call_callback(); free_job(j); return; } @@ -3373,7 +3373,7 @@ namespace libtorrent #if TORRENT_USE_ASSERTS j->callback_called = true; #endif - if (j->callback) j->callback(j); + j->call_callback(); to_delete[cnt++] = j; j = next; if (cnt == to_delete.size()) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index e0ca16a88..411aef49d 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -2961,15 +2961,15 @@ namespace libtorrent disconnect(errors::torrent_paused, op_bittorrent); } - void peer_connection::on_disk_write_complete(disk_io_job const* j + void peer_connection::on_disk_write_complete(storage_error const& error , peer_request p, std::shared_ptr t) { TORRENT_ASSERT(is_single_thread()); #ifndef TORRENT_DISABLE_LOGGING if (should_log(peer_log_alert::info)) { - peer_log(peer_log_alert::info, "FILE_ASYNC_WRITE_COMPLETE", "ret: %d piece: %d s: %x l: %x e: %s" - , j->ret, p.piece, p.start, p.length, j->error.ec.message().c_str()); + peer_log(peer_log_alert::info, "FILE_ASYNC_WRITE_COMPLETE", "piece: %d s: %x l: %x e: %s" + , p.piece, p.start, p.length, error.ec.message().c_str()); } #endif @@ -2991,7 +2991,7 @@ namespace libtorrent if (!t) { - disconnect(j->error.ec, op_file_write); + disconnect(error.ec, op_file_write); return; } @@ -3001,12 +3001,12 @@ namespace libtorrent piece_block const block_finished(p.piece, p.start / t->block_size()); - if (j->ret < 0) + if (error) { - // we failed to write j->piece to disk tell the piece picker + // we failed to write the piece to disk tell the piece picker // this will block any other peer from issuing requests // to this piece, until we've cleared it. - if (j->error.ec == boost::asio::error::operation_aborted) + if (error.ec == boost::asio::error::operation_aborted) { if (t->has_picker()) t->picker().mark_as_canceled(block_finished, nullptr); @@ -3024,7 +3024,7 @@ namespace libtorrent // when this returns, all outstanding jobs to the // piece are done, and we can restore it, allowing // new requests to it - m_disk_thread.async_clear_piece(&t->storage(), j->piece + m_disk_thread.async_clear_piece(&t->storage(), p.piece , std::bind(&torrent::on_piece_fail_sync, t, _1, block_finished)); } else @@ -3033,24 +3033,22 @@ namespace libtorrent // exit this function early, no need to keep the picker // state up-to-date, right? disk_io_job sj; - sj.piece = j->piece; + sj.piece = p.piece; t->on_piece_fail_sync(&sj, block_finished); } } t->update_gauge(); // handle_disk_error may disconnect us - t->handle_disk_error("write", j->error, this, torrent::disk_class::write); + t->handle_disk_error("write", error, this, torrent::disk_class::write); return; } - TORRENT_ASSERT(j->ret == p.length); - if (!t->has_picker()) return; piece_picker& picker = t->picker(); - TORRENT_ASSERT(p.piece == j->piece); - TORRENT_ASSERT(p.start == j->d.io.offset); + TORRENT_ASSERT(p.piece == p.piece); + TORRENT_ASSERT(p.start == p.start); TORRENT_ASSERT(picker.num_peers(block_finished) == 0); // std::fprintf(stderr, "peer_connection mark_as_finished peer: %p piece: %d block: %d\n" @@ -5114,8 +5112,8 @@ namespace libtorrent // this means we're in seed mode and we haven't yet // verified this piece (r.piece) m_disk_thread.async_hash(&t->storage(), r.piece, 0 - , std::bind(&peer_connection::on_seed_mode_hashed, self(), _1) - , this); + , std::bind(&peer_connection::on_seed_mode_hashed, self() + , _1, _2, _3, _4), this); t->verifying(r.piece); continue; } @@ -5151,7 +5149,7 @@ namespace libtorrent m_disk_thread.async_read(&t->storage(), r , std::bind(&peer_connection::on_disk_read_complete - , self(), _1, r, clock_type::now()), this); + , self(), _1, _2, _3, _4, r, clock_type::now()), this); } m_last_sent_payload = clock_type::now(); m_requests.erase(m_requests.begin() + i); @@ -5168,7 +5166,8 @@ namespace libtorrent // this is called when a previously unchecked piece has been // checked, while in seed-mode - void peer_connection::on_seed_mode_hashed(disk_io_job const* j) + void peer_connection::on_seed_mode_hashed(int const + , int const piece, sha1_hash const& piece_hash, storage_error const& error) { TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; @@ -5180,32 +5179,32 @@ namespace libtorrent if (!t || t->is_aborted()) return; - if (j->error) + if (error) { - t->handle_disk_error("hash", j->error, this); + t->handle_disk_error("hash", error, this); t->leave_seed_mode(false); return; } // we're using the piece hashes here, we need the torrent to be loaded if (!m_settings.get_bool(settings_pack::disable_hash_checks) - && sha1_hash(j->d.piece_hash) != t->torrent_file().hash_for_piece(j->piece)) + && piece_hash != t->torrent_file().hash_for_piece(piece)) { #ifndef TORRENT_DISABLE_LOGGING peer_log(peer_log_alert::info, "SEED_MODE_FILE_HASH" - , "piece: %d failed", j->piece); + , "piece: %d failed", piece); #endif t->leave_seed_mode(false); } else { - TORRENT_ASSERT(t->verifying_piece(j->piece)); - if (t->seed_mode()) t->verified(j->piece); + TORRENT_ASSERT(t->verifying_piece(piece)); + if (t->seed_mode()) t->verified(piece); #ifndef TORRENT_DISABLE_LOGGING peer_log(peer_log_alert::info, "SEED_MODE_FILE_HASH" - , "piece: %d passed", j->piece); + , "piece: %d passed", piece); #endif if (t) { @@ -5219,7 +5218,8 @@ namespace libtorrent fill_send_buffer(); } - void peer_connection::on_disk_read_complete(disk_io_job const* j + void peer_connection::on_disk_read_complete(aux::block_cache_reference ref + , char* disk_block, int const flags, storage_error const& error , peer_request r, time_point issue_time) { TORRENT_ASSERT(is_single_thread()); @@ -5233,35 +5233,35 @@ namespace libtorrent if (should_log(peer_log_alert::info)) { peer_log(peer_log_alert::info, "FILE_ASYNC_READ_COMPLETE" - , "ret: %d piece: %d s: %x l: %x b: %p c: %s e: %s rtt: %d us" - , j->ret, r.piece, r.start, r.length - , static_cast(j->buffer.disk_block) - , (j->flags & disk_io_job::cache_hit ? "cache hit" : "cache miss") - , j->error.ec.message().c_str(), disk_rtt); + , "piece: %d s: %x l: %x b: %p c: %s e: %s rtt: %d us" + , r.piece, r.start, r.length + , static_cast(disk_block) + , (flags & disk_io_job::cache_hit ? "cache hit" : "cache miss") + , error.ec.message().c_str(), disk_rtt); } #endif m_reading_bytes -= r.length; std::shared_ptr t = m_torrent.lock(); - if (j->ret < 0) + if (error) { if (!t) { - disconnect(j->error.ec, op_file_read); + disconnect(error.ec, op_file_read); return; } - TORRENT_ASSERT(j->buffer.disk_block == nullptr); + TORRENT_ASSERT(disk_block == nullptr); write_dont_have(r.piece); write_reject_request(r); if (t->alerts().should_post()) - t->alerts().emplace_alert(j->error.ec - , t->resolve_filename(j->error.file) - , j->error.operation_str(), t->get_handle()); + t->alerts().emplace_alert(error.ec + , t->resolve_filename(error.file) + , error.operation_str(), t->get_handle()); ++m_disk_read_failures; - if (m_disk_read_failures > 100) disconnect(j->error.ec, op_file_read); + if (m_disk_read_failures > 100) disconnect(error.ec, op_file_read); return; } @@ -5270,12 +5270,10 @@ namespace libtorrent // block, the peer is still useful m_disk_read_failures = 0; - TORRENT_ASSERT(j->ret == r.length); - // even if we're disconnecting, we need to free this block // otherwise the disk thread will hang, waiting for the network // thread to be done with it - disk_buffer_holder buffer(m_allocator, j->d.io.ref, j->buffer.disk_block); + disk_buffer_holder buffer(m_allocator, ref, disk_block); if (t && m_settings.get_int(settings_pack::suggest_mode) == settings_pack::suggest_read_cache) @@ -5290,14 +5288,7 @@ namespace libtorrent if (!t) { - disconnect(j->error.ec, op_file_read); - return; - } - - if (j->ret != r.length) - { - // handle_disk_error may disconnect us - t->handle_disk_error("read", j->error, this); + disconnect(error.ec, op_file_read); return; } @@ -5312,7 +5303,7 @@ namespace libtorrent // if it's rare enough to make it into the suggested piece // push another piece out if (m_settings.get_int(settings_pack::suggest_mode) == settings_pack::suggest_read_cache - && (j->flags & disk_io_job::cache_hit) == 0) + && (flags & disk_io_job::cache_hit) == 0) { t->add_suggest_piece(r.piece); } diff --git a/src/smart_ban.cpp b/src/smart_ban.cpp index 320e84da2..f4c487090 100644 --- a/src/smart_ban.cpp +++ b/src/smart_ban.cpp @@ -95,7 +95,7 @@ namespace { m_torrent.session().disk_thread().async_read(&m_torrent.storage() , r, std::bind(&smart_ban_plugin::on_read_ok_block - , shared_from_this(), *i, i->second.peer->address(), _1) + , shared_from_this(), *i, i->second.peer->address(), _1, _2, _3, _4) , reinterpret_cast(1)); m_block_hashes.erase(i++); } @@ -152,7 +152,7 @@ namespace // block read will have been deleted by the time it gets back to the network thread m_torrent.session().disk_thread().async_read(&m_torrent.storage(), r , std::bind(&smart_ban_plugin::on_read_failed_block - , shared_from_this(), pb, (*i)->address(), _1) + , shared_from_this(), pb, (*i)->address(), _1, _2, _3, _4) , reinterpret_cast(1) , disk_io_job::force_copy); } @@ -175,17 +175,21 @@ namespace sha1_hash digest; }; - void on_read_failed_block(piece_block b, address a, disk_io_job const* j) + void on_read_failed_block(piece_block b, address a + , aux::block_cache_reference ref, char* disk_block, int + , storage_error const& error) { TORRENT_ASSERT(m_torrent.session().is_single_thread()); - disk_buffer_holder buffer(m_torrent.session(), j->d.io.ref, j->buffer.disk_block); + disk_buffer_holder buffer(m_torrent.session(), ref, disk_block); // ignore read errors - if (j->ret != j->d.io.buffer_size) return; + if (error) return; + + int const size = m_torrent.torrent_file().piece_size(b.piece_index); hasher h; - h.update(j->buffer.disk_block, j->d.io.buffer_size); + h.update(disk_block, size); h.update(reinterpret_cast(&m_salt), sizeof(m_salt)); std::pair const range @@ -257,17 +261,21 @@ namespace #endif } - void on_read_ok_block(std::pair b, address a, disk_io_job const* j) + void on_read_ok_block(std::pair b, address a + , aux::block_cache_reference ref, char* disk_block, int + , storage_error const& error) { TORRENT_ASSERT(m_torrent.session().is_single_thread()); - disk_buffer_holder buffer(m_torrent.session(), j->d.io.ref, j->buffer.disk_block); + disk_buffer_holder buffer(m_torrent.session(), ref, disk_block); // ignore read errors - if (j->ret != j->d.io.buffer_size) return; + if (error) return; + + int const size = m_torrent.torrent_file().piece_size(b.first.piece_index); hasher h; - h.update(j->buffer.disk_block, j->d.io.buffer_size); + h.update(disk_block, size); h.update(reinterpret_cast(&m_salt), sizeof(m_salt)); sha1_hash const ok_digest = h.final(); diff --git a/src/torrent.cpp b/src/torrent.cpp index dd150dc9e..b6c7c06b3 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -860,7 +860,7 @@ namespace libtorrent r.length = (std::min)(piece_size - r.start, block_size()); m_ses.disk_thread().async_read(&storage(), r , std::bind(&torrent::on_disk_read_complete - , shared_from_this(), _1, r, rp), reinterpret_cast(1)); + , shared_from_this(), _1, _2, _3, _4, r, rp), reinterpret_cast(1)); } } @@ -1128,24 +1128,25 @@ namespace libtorrent } catch (...) { handle_exception(); } - void torrent::on_disk_read_complete(disk_io_job const* j, peer_request r - , std::shared_ptr rp) try + void torrent::on_disk_read_complete(aux::block_cache_reference ref + , char* block, int, storage_error const& se + , peer_request r, std::shared_ptr rp) try { // hold a reference until this function returns TORRENT_ASSERT(is_single_thread()); - disk_buffer_holder buffer(m_ses, j->d.io.ref, j->buffer.disk_block); + disk_buffer_holder buffer(m_ses, ref, block); --rp->blocks_left; - if (j->ret != r.length) + if (se) { rp->fail = true; - rp->error = j->error.ec; - handle_disk_error("read", j->error); + rp->error = se.ec; + handle_disk_error("read", se); } else { - std::memcpy(rp->piece_data.get() + r.start, j->buffer.disk_block, r.length); + std::memcpy(rp->piece_data.get() + r.start, block, r.length); } if (rp->blocks_left == 0) @@ -1218,7 +1219,7 @@ namespace libtorrent // TODO: 3 there's some duplication between this function and // peer_connection::incoming_piece(). is there a way to merge something? - void torrent::add_piece(int piece, char const* data, int flags) + void torrent::add_piece(int piece, char const* data, int const flags) { TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(piece >= 0 && piece < m_torrent_file->num_pieces()); @@ -1281,7 +1282,7 @@ namespace libtorrent picker().dec_refcount(piece, nullptr); } - void torrent::on_disk_write_complete(disk_io_job const* j + void torrent::on_disk_write_complete(storage_error const& error , peer_request p) try { TORRENT_ASSERT(is_single_thread()); @@ -1295,9 +1296,9 @@ namespace libtorrent if (m_abort) return; piece_block block_finished(p.piece, p.start / block_size()); - if (j->ret == -1) + if (error) { - handle_disk_error("write", j->error); + handle_disk_error("write", error); return; } @@ -2256,7 +2257,7 @@ namespace libtorrent m_ses.disk_thread().async_hash(m_storage.get(), m_checking_piece++ , disk_io_job::sequential_access | disk_io_job::volatile_read , std::bind(&torrent::on_piece_hashed - , shared_from_this(), _1), reinterpret_cast(1)); + , shared_from_this(), _1, _2, _3, _4), reinterpret_cast(1)); if (m_checking_piece >= m_torrent_file->num_pieces()) break; } #ifndef TORRENT_DISABLE_LOGGING @@ -2266,14 +2267,15 @@ namespace libtorrent // This is only used for checking of torrents. i.e. force-recheck or initial checking // of existing files - void torrent::on_piece_hashed(disk_io_job const* j) try + void torrent::on_piece_hashed(int const status, int const piece + , sha1_hash const& piece_hash, storage_error const& error) try { TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; if (m_abort) return; - if (j->ret == disk_interface::disk_check_aborted) + if (status == disk_interface::disk_check_aborted) { m_checking_piece = 0; m_num_checked_pieces = 0; @@ -2288,21 +2290,21 @@ namespace libtorrent ++m_num_checked_pieces; - if (j->ret < 0) + if (status < 0) { - if (j->error.ec == boost::system::errc::no_such_file_or_directory - || j->error.ec == boost::asio::error::eof + if (error.ec == boost::system::errc::no_such_file_or_directory + || error.ec == boost::asio::error::eof #ifdef TORRENT_WINDOWS - || j->error.ec == error_code(ERROR_HANDLE_EOF, system_category()) + || error.ec == error_code(ERROR_HANDLE_EOF, system_category()) #endif ) { - TORRENT_ASSERT(j->error.file >= 0); + TORRENT_ASSERT(error.file >= 0); // skip this file by updating m_checking_piece to the first piece following it file_storage const& st = m_torrent_file->files(); - std::uint64_t file_size = st.file_size(j->error.file); - int last = st.map_file(j->error.file, file_size, 0).piece; + std::uint64_t file_size = st.file_size(error.file); + int last = st.map_file(error.file, file_size, 0).piece; if (m_checking_piece < last) { int diff = last - m_checking_piece; @@ -2315,16 +2317,19 @@ namespace libtorrent m_checking_piece = 0; m_num_checked_pieces = 0; if (m_ses.alerts().should_post()) - m_ses.alerts().emplace_alert(j->error.ec, - resolve_filename(j->error.file), j->error.operation_str(), get_handle()); + m_ses.alerts().emplace_alert(error.ec, + resolve_filename(error.file), error.operation_str(), get_handle()); #ifndef TORRENT_DISABLE_LOGGING if (should_log()) - debug_log("on_piece_hashed, fatal disk error: (%d) %s", j->error.ec.value(), j->error.ec.message().c_str()); + { + debug_log("on_piece_hashed, fatal disk error: (%d) %s", error.ec.value() + , error.ec.message().c_str()); + } #endif auto_managed(false); pause(); - set_error(j->error.ec, j->error.file); + set_error(error.ec, error.file); // recalculate auto-managed torrents sooner // in order to start checking the next torrent @@ -2336,21 +2341,21 @@ namespace libtorrent m_progress_ppm = std::int64_t(m_num_checked_pieces) * 1000000 / torrent_file().num_pieces(); if (settings().get_bool(settings_pack::disable_hash_checks) - || sha1_hash(j->d.piece_hash) == m_torrent_file->hash_for_piece(j->piece)) + || piece_hash == m_torrent_file->hash_for_piece(piece)) { if (has_picker() || !m_have_all) { need_picker(); - m_picker->we_have(j->piece); + m_picker->we_have(piece); update_gauge(); } - we_have(j->piece); + we_have(piece); } else { // if the hash failed, remove it from the cache if (m_storage) - m_ses.disk_thread().clear_piece(m_storage.get(), j->piece); + m_ses.disk_thread().clear_piece(m_storage.get(), piece); } if (m_num_checked_pieces < m_torrent_file->num_pieces()) @@ -2383,7 +2388,7 @@ namespace libtorrent m_ses.disk_thread().async_hash(m_storage.get(), m_checking_piece++ , disk_io_job::sequential_access | disk_io_job::volatile_read , std::bind(&torrent::on_piece_hashed - , shared_from_this(), _1), reinterpret_cast(1)); + , shared_from_this(), _1, _2, _3, _4), reinterpret_cast(1)); #ifndef TORRENT_DISABLE_LOGGING debug_log("on_piece_hashed, m_checking_piece: %d", m_checking_piece); #endif @@ -3658,24 +3663,25 @@ namespace libtorrent TORRENT_ASSERT(st.total_done >= st.total_wanted_done); } - void torrent::on_piece_verified(disk_io_job const* j) try + void torrent::on_piece_verified(int const status, int const piece + , sha1_hash const& piece_hash, storage_error const& error) try { TORRENT_ASSERT(is_single_thread()); if (m_abort) return; - int ret = j->ret; + int ret = status; if (settings().get_bool(settings_pack::disable_hash_checks)) { ret = 0; } else if (ret == -1) { - handle_disk_error("piece_verified", j->error); + handle_disk_error("piece_verified", error); } else { - if (sha1_hash(j->d.piece_hash) != m_torrent_file->hash_for_piece(j->piece)) + if (sha1_hash(piece_hash) != m_torrent_file->hash_for_piece(piece)) ret = -2; } @@ -3687,10 +3693,10 @@ namespace libtorrent if (should_log()) { debug_log("*** PIECE_FINISHED [ p: %d | chk: %s | size: %d ]" - , j->piece, ((ret == 0) + , piece, ((ret == 0) ?"passed":ret == -1 ?"disk failed":"failed") - , m_torrent_file->piece_size(j->piece)); + , m_torrent_file->piece_size(piece)); } #endif TORRENT_ASSERT(valid_metadata()); @@ -3702,7 +3708,7 @@ namespace libtorrent need_picker(); - TORRENT_ASSERT(!m_picker->have_piece(j->piece)); + TORRENT_ASSERT(!m_picker->have_piece(piece)); state_updated(); @@ -3712,21 +3718,21 @@ namespace libtorrent // called, and the piece is no longer finished. // in this case, we have to ignore the fact that // it passed the check - if (!m_picker->is_piece_finished(j->piece)) return; + if (!m_picker->is_piece_finished(piece)) return; if (ret == 0) { // the following call may cause picker to become invalid // in case we just became a seed - piece_passed(j->piece); + piece_passed(piece); // if we're in seed mode, we just acquired this piece // mark it as verified - if (m_seed_mode) verified(j->piece); + if (m_seed_mode) verified(piece); } else if (ret == -2) { // piece_failed() will restore the piece - piece_failed(j->piece); + piece_failed(piece); } else { @@ -10257,9 +10263,10 @@ namespace libtorrent TORRENT_ASSERT(m_storage.get()); m_ses.disk_thread().async_hash(m_storage.get(), piece, 0 - , std::bind(&torrent::on_piece_verified, shared_from_this(), _1) + , std::bind(&torrent::on_piece_verified, shared_from_this(), _1, _2, _3, _4) , reinterpret_cast(1)); } + announce_entry* torrent::find_tracker(std::string const& url) { auto i = std::find_if(m_trackers.begin(), m_trackers.end()