start chipping away at removing disk_io_job from the disk_interface
This commit is contained in:
parent
8011ab57be
commit
fc9dabe1ab
|
@ -60,14 +60,14 @@ namespace libtorrent
|
|||
};
|
||||
|
||||
virtual void async_read(storage_interface* storage, peer_request const& r
|
||||
, std::function<void(disk_io_job const*)> handler, void* requester
|
||||
, int flags = 0) = 0;
|
||||
, std::function<void(aux::block_cache_reference ref, char* block
|
||||
, int flags, storage_error const& se)> handler, void* requester, int flags = 0) = 0;
|
||||
virtual void async_write(storage_interface* storage, peer_request const& r
|
||||
, disk_buffer_holder buffer
|
||||
, std::function<void(disk_io_job const*)> handler
|
||||
, std::function<void(storage_error const&)> handler
|
||||
, int flags = 0) = 0;
|
||||
virtual void async_hash(storage_interface* storage, int piece, int flags
|
||||
, std::function<void(disk_io_job const*)> handler, void* requester) = 0;
|
||||
, std::function<void(int, int, sha1_hash const&, storage_error const&)> handler, void* requester) = 0;
|
||||
virtual void async_move_storage(storage_interface* storage, std::string const& p, int flags
|
||||
, std::function<void(disk_io_job const*)> handler) = 0;
|
||||
virtual void async_release_files(storage_interface* storage
|
||||
|
|
|
@ -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 <boost/variant/variant.hpp>
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -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_interface> storage;
|
||||
|
||||
// this is called when operation completes
|
||||
std::function<void(disk_io_job const*)> callback;
|
||||
|
||||
using read_handler = std::function<void(aux::block_cache_reference ref
|
||||
, char* block, int flags, storage_error const& se)>;
|
||||
using write_handler = std::function<void(storage_error const&)>;
|
||||
using hash_handler = std::function<void(int, int, sha1_hash const&, storage_error const&)>;
|
||||
using generic_handler = std::function<void(disk_io_job const*)>;
|
||||
|
||||
boost::variant<read_handler, write_handler, hash_handler, generic_handler> callback;
|
||||
|
||||
// the error code from the file operation
|
||||
// on error, this also contains the path of the
|
||||
|
|
|
@ -292,14 +292,14 @@ namespace libtorrent
|
|||
void abort(bool wait);
|
||||
|
||||
void async_read(storage_interface* storage, peer_request const& r
|
||||
, std::function<void(disk_io_job const*)> handler, void* requester
|
||||
, int flags = 0) override;
|
||||
, std::function<void(aux::block_cache_reference ref, char* block
|
||||
, int flags, storage_error const& se)> handler, void* requester, int flags = 0) override;
|
||||
void async_write(storage_interface* storage, peer_request const& r
|
||||
, disk_buffer_holder buffer
|
||||
, std::function<void(disk_io_job const*)> handler
|
||||
, std::function<void(storage_error const&)> handler
|
||||
, int flags = 0) override;
|
||||
void async_hash(storage_interface* storage, int piece, int flags
|
||||
, std::function<void(disk_io_job const*)> handler, void* requester) override;
|
||||
, std::function<void(int, int, sha1_hash const&, storage_error const&)> handler, void* requester) override;
|
||||
void async_move_storage(storage_interface* storage, std::string const& p, int flags
|
||||
, std::function<void(disk_io_job const*)> handler) override;
|
||||
void async_release_files(storage_interface* storage
|
||||
|
|
|
@ -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<torrent> 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();
|
||||
|
||||
|
|
|
@ -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<read_piece_struct> 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<read_piece_struct> 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
|
||||
|
|
|
@ -158,34 +158,42 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void on_hash(disk_io_job const* j, create_torrent* t
|
||||
, std::shared_ptr<storage_interface> storage, disk_io_thread* iothread
|
||||
, int* piece_counter, int* completed_piece
|
||||
, std::function<void(int)> const* f, error_code* ec)
|
||||
struct hash_state
|
||||
{
|
||||
if (j->ret != 0)
|
||||
create_torrent& ct;
|
||||
std::shared_ptr<storage_interface> storage;
|
||||
disk_io_thread& iothread;
|
||||
int piece_counter;
|
||||
int completed_piece;
|
||||
std::function<void(int)> 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1509,8 +1509,8 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
void disk_io_thread::async_read(storage_interface* storage, peer_request const& r
|
||||
, std::function<void(disk_io_job const*)> handler, void* requester
|
||||
, int const flags)
|
||||
, std::function<void(aux::block_cache_reference ref, char* block
|
||||
, int flags, storage_error const& se)> 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<void(disk_io_job const*)> handler
|
||||
, std::function<void(storage_error const&)> 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<void(disk_io_job const*)> handler, void* requester)
|
||||
, std::function<void(int, int, sha1_hash const&, storage_error const&)> 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())
|
||||
|
|
|
@ -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<torrent> 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<void*>(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<void*>(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<torrent> 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<file_error_alert>())
|
||||
t->alerts().emplace_alert<file_error_alert>(j->error.ec
|
||||
, t->resolve_filename(j->error.file)
|
||||
, j->error.operation_str(), t->get_handle());
|
||||
t->alerts().emplace_alert<file_error_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);
|
||||
}
|
||||
|
|
|
@ -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<void*>(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<torrent_peer*>(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<char const*>(&m_salt), sizeof(m_salt));
|
||||
|
||||
std::pair<peer_list::iterator, peer_list::iterator> const range
|
||||
|
@ -257,17 +261,21 @@ namespace
|
|||
#endif
|
||||
}
|
||||
|
||||
void on_read_ok_block(std::pair<piece_block, block_entry> b, address a, disk_io_job const* j)
|
||||
void on_read_ok_block(std::pair<piece_block, block_entry> 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<char const*>(&m_salt), sizeof(m_salt));
|
||||
sha1_hash const ok_digest = h.final();
|
||||
|
||||
|
|
|
@ -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<void*>(1));
|
||||
, shared_from_this(), _1, _2, _3, _4, r, rp), reinterpret_cast<void*>(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<read_piece_struct> 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<read_piece_struct> 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<void*>(1));
|
||||
, shared_from_this(), _1, _2, _3, _4), reinterpret_cast<void*>(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<file_error_alert>())
|
||||
m_ses.alerts().emplace_alert<file_error_alert>(j->error.ec,
|
||||
resolve_filename(j->error.file), j->error.operation_str(), get_handle());
|
||||
m_ses.alerts().emplace_alert<file_error_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<void*>(1));
|
||||
, shared_from_this(), _1, _2, _3, _4), reinterpret_cast<void*>(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<void*>(1));
|
||||
}
|
||||
|
||||
announce_entry* torrent::find_tracker(std::string const& url)
|
||||
{
|
||||
auto i = std::find_if(m_trackers.begin(), m_trackers.end()
|
||||
|
|
Loading…
Reference in New Issue