cleaning up of disk_interface and improving type safety (#1353)

cleaned up disk_interface and improved type safety. removed unused disk status code disk_check_aborted, and removed status code return value for async_hash
This commit is contained in:
Arvid Norberg 2016-11-26 01:51:47 -05:00 committed by GitHub
parent 5c8e6d6e97
commit 15ab8f387b
16 changed files with 215 additions and 245 deletions

View File

@ -1,3 +1,4 @@
* tweaked storage_interface to have stronger type safety
* deprecate relative times in torrent_status, replaced by std::chrono::time_point * deprecate relative times in torrent_status, replaced by std::chrono::time_point
* refactor in alert types to use more const fields and more clear API * refactor in alert types to use more const fields and more clear API
* changed session_stats_alert counters type to signed (std::int64_t) * changed session_stats_alert counters type to signed (std::int64_t)

View File

@ -45,24 +45,30 @@ namespace libtorrent
struct file_pool; struct file_pool;
struct add_torrent_params; struct add_torrent_params;
struct cache_status; struct cache_status;
struct disk_buffer_holder;
struct counters;
enum class status_t : std::uint8_t
{
// return values from check_fastresume, and move_storage
no_error,
fatal_disk_error,
need_full_check,
file_exist
};
struct TORRENT_EXTRA_EXPORT disk_interface struct TORRENT_EXTRA_EXPORT disk_interface
{ {
enum return_t
{
// return values from check_fastresume, and move_storage
no_error = 0,
fatal_disk_error = -1,
need_full_check = -2,
disk_check_aborted = -3,
file_exist = -4
};
enum flags_t enum flags_t
{ {
sequential_access = 0x1,
// this flag is set on a job when a read operation did // this flag is set on a job when a read operation did
// not hit the disk, but found the data in the read cache. // not hit the disk, but found the data in the read cache.
cache_hit = 0x2, cache_hit = 0x2,
// don't keep the read block in cache
volatile_read = 0x10,
}; };
virtual void async_read(storage_interface* storage, peer_request const& r virtual void async_read(storage_interface* storage, peer_request const& r
@ -73,15 +79,15 @@ namespace libtorrent
, std::function<void(storage_error const&)> handler , std::function<void(storage_error const&)> handler
, std::uint8_t flags = 0) = 0; , std::uint8_t flags = 0) = 0;
virtual void async_hash(storage_interface* storage, int piece, std::uint8_t flags virtual void async_hash(storage_interface* storage, int piece, std::uint8_t flags
, std::function<void(int, int, sha1_hash const&, storage_error const&)> handler, void* requester) = 0; , std::function<void(int, sha1_hash const&, storage_error const&)> handler, void* requester) = 0;
virtual void async_move_storage(storage_interface* storage, std::string const& p, std::uint8_t flags virtual void async_move_storage(storage_interface* storage, std::string const& p, std::uint8_t flags
, std::function<void(int, std::string const&, storage_error const&)> handler) = 0; , std::function<void(status_t, std::string const&, storage_error const&)> handler) = 0;
virtual void async_release_files(storage_interface* storage virtual void async_release_files(storage_interface* storage
, std::function<void()> handler = std::function<void()>()) = 0; , std::function<void()> handler = std::function<void()>()) = 0;
virtual void async_check_files(storage_interface* storage virtual void async_check_files(storage_interface* storage
, add_torrent_params const* resume_data , add_torrent_params const* resume_data
, std::vector<std::string>& links , std::vector<std::string>& links
, std::function<void(int, storage_error const&)> handler) = 0; , std::function<void(status_t, storage_error const&)> handler) = 0;
virtual void async_flush_piece(storage_interface* storage, int piece virtual void async_flush_piece(storage_interface* storage, int piece
, std::function<void()> handler = std::function<void()>()) = 0; , std::function<void()> handler = std::function<void()>()) = 0;
virtual void async_stop_torrent(storage_interface* storage virtual void async_stop_torrent(storage_interface* storage

View File

@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_request.hpp" #include "libtorrent/peer_request.hpp"
#include "libtorrent/aux_/block_cache_reference.hpp" #include "libtorrent/aux_/block_cache_reference.hpp"
#include "libtorrent/sha1_hash.hpp" #include "libtorrent/sha1_hash.hpp"
#include "libtorrent/disk_interface.hpp"
#include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp"
#include <boost/variant/variant.hpp> #include <boost/variant/variant.hpp>
@ -99,8 +100,6 @@ namespace libtorrent
enum flags_t enum flags_t
{ {
sequential_access = 0x1,
// force making a copy of the cached block, rather // force making a copy of the cached block, rather
// than getting a reference to the block already in // than getting a reference to the block already in
// the cache. // the cache.
@ -112,9 +111,6 @@ namespace libtorrent
// to lower the fence when the job has completed // to lower the fence when the job has completed
fence = 0x8, fence = 0x8,
// don't keep the read block in cache
volatile_read = 0x10,
// this job is currently being performed, or it's hanging // this job is currently being performed, or it's hanging
// on a cache piece that may be flushed soon // on a cache piece that may be flushed soon
in_progress = 0x20 in_progress = 0x20
@ -151,10 +147,10 @@ namespace libtorrent
using read_handler = std::function<void(aux::block_cache_reference ref using read_handler = std::function<void(aux::block_cache_reference ref
, char* block, int flags, storage_error const& se)>; , char* block, int flags, storage_error const& se)>;
using write_handler = std::function<void(storage_error const&)>; using write_handler = std::function<void(storage_error const&)>;
using hash_handler = std::function<void(int, int, sha1_hash const&, storage_error const&)>; using hash_handler = std::function<void(int, sha1_hash const&, storage_error const&)>;
using move_handler = std::function<void(int, std::string const&, storage_error const&)>; using move_handler = std::function<void(status_t, std::string const&, storage_error const&)>;
using release_handler = std::function<void()>; using release_handler = std::function<void()>;
using check_handler = std::function<void(int, storage_error const&)>; using check_handler = std::function<void(status_t, storage_error const&)>;
using rename_handler = std::function<void(std::string const&, int, storage_error const&)>; using rename_handler = std::function<void(std::string const&, int, storage_error const&)>;
using clear_piece_handler = std::function<void(int)>; using clear_piece_handler = std::function<void(int)>;
@ -215,10 +211,8 @@ namespace libtorrent
// the type of job this is // the type of job this is
std::uint32_t action:8; std::uint32_t action:8;
enum { operation_failed = -1 };
// return value of operation // return value of operation
std::int32_t ret = 0; status_t ret = status_t::no_error;
// flags controlling this job // flags controlling this job
std::uint8_t flags = 0; std::uint8_t flags = 0;

View File

@ -299,9 +299,9 @@ namespace libtorrent
, std::function<void(storage_error const&)> handler , std::function<void(storage_error const&)> handler
, std::uint8_t flags = 0) override; , std::uint8_t flags = 0) override;
void async_hash(storage_interface* storage, int piece, std::uint8_t flags void async_hash(storage_interface* storage, int piece, std::uint8_t flags
, std::function<void(int, int, sha1_hash const&, storage_error const&)> handler, void* requester) override; , std::function<void(int, sha1_hash const&, storage_error const&)> handler, void* requester) override;
void async_move_storage(storage_interface* storage, std::string const& p, std::uint8_t flags void async_move_storage(storage_interface* storage, std::string const& p, std::uint8_t flags
, std::function<void(int, std::string const&, storage_error const&)> handler) override; , std::function<void(status_t, std::string const&, storage_error const&)> handler) override;
void async_release_files(storage_interface* storage void async_release_files(storage_interface* storage
, std::function<void()> handler = std::function<void()>()) override; , std::function<void()> handler = std::function<void()>()) override;
void async_delete_files(storage_interface* storage, int options void async_delete_files(storage_interface* storage, int options
@ -309,7 +309,7 @@ namespace libtorrent
void async_check_files(storage_interface* storage void async_check_files(storage_interface* storage
, add_torrent_params const* resume_data , add_torrent_params const* resume_data
, std::vector<std::string>& links , std::vector<std::string>& links
, std::function<void(int, storage_error const&)> handler) override; , std::function<void(status_t, storage_error const&)> handler) override;
void async_rename_file(storage_interface* storage, int index, std::string const& name void async_rename_file(storage_interface* storage, int index, std::string const& name
, std::function<void(std::string const&, int, storage_error const&)> handler) override; , std::function<void(std::string const&, int, storage_error const&)> handler) override;
void async_stop_torrent(storage_interface* storage void async_stop_torrent(storage_interface* storage
@ -372,29 +372,29 @@ namespace libtorrent
void maybe_issue_queued_read_jobs(cached_piece_entry* pe, void maybe_issue_queued_read_jobs(cached_piece_entry* pe,
jobqueue_t& completed_jobs); jobqueue_t& completed_jobs);
int do_read(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_read(disk_io_job* j, jobqueue_t& completed_jobs);
int do_uncached_read(disk_io_job* j); status_t do_uncached_read(disk_io_job* j);
int do_write(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_write(disk_io_job* j, jobqueue_t& completed_jobs);
int do_uncached_write(disk_io_job* j); status_t do_uncached_write(disk_io_job* j);
int do_hash(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_hash(disk_io_job* j, jobqueue_t& completed_jobs);
int do_uncached_hash(disk_io_job* j); status_t do_uncached_hash(disk_io_job* j);
int do_move_storage(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_move_storage(disk_io_job* j, jobqueue_t& completed_jobs);
int do_release_files(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_release_files(disk_io_job* j, jobqueue_t& completed_jobs);
int do_delete_files(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_delete_files(disk_io_job* j, jobqueue_t& completed_jobs);
int do_check_fastresume(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_check_fastresume(disk_io_job* j, jobqueue_t& completed_jobs);
int do_rename_file(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_rename_file(disk_io_job* j, jobqueue_t& completed_jobs);
int do_stop_torrent(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_stop_torrent(disk_io_job* j, jobqueue_t& completed_jobs);
int do_read_and_hash(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_read_and_hash(disk_io_job* j, jobqueue_t& completed_jobs);
int do_flush_piece(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_flush_piece(disk_io_job* j, jobqueue_t& completed_jobs);
int do_flush_hashed(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_flush_hashed(disk_io_job* j, jobqueue_t& completed_jobs);
int do_flush_storage(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_flush_storage(disk_io_job* j, jobqueue_t& completed_jobs);
int do_trim_cache(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_trim_cache(disk_io_job* j, jobqueue_t& completed_jobs);
int do_file_priority(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_file_priority(disk_io_job* j, jobqueue_t& completed_jobs);
int do_clear_piece(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_clear_piece(disk_io_job* j, jobqueue_t& completed_jobs);
int do_resolve_links(disk_io_job* j, jobqueue_t& completed_jobs); status_t do_resolve_links(disk_io_job* j, jobqueue_t& completed_jobs);
void call_job_handlers(); void call_job_handlers();
@ -425,17 +425,6 @@ namespace libtorrent
jobqueue_t m_queued_jobs; jobqueue_t m_queued_jobs;
}; };
enum return_value_t
{
// the do_* functions can return this to indicate the disk
// job did not complete immediately, and shouldn't be posted yet
defer_handler = -200,
// the job cannot be completed right now, put it back in the
// queue and try again later
retry_job = -201
};
// returns true if the thread should exit // returns true if the thread should exit
static bool wait_for_job(job_queue& jobq, disk_io_thread_pool& threads static bool wait_for_job(job_queue& jobq, disk_io_thread_pool& threads
, std::unique_lock<std::mutex>& l); , std::unique_lock<std::mutex>& l);

View File

@ -64,6 +64,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/span.hpp" #include "libtorrent/span.hpp"
#include "libtorrent/piece_block.hpp" #include "libtorrent/piece_block.hpp"
#include "libtorrent/peer_info.hpp" #include "libtorrent/peer_info.hpp"
#include "libtorrent/disk_interface.hpp"
#include <ctime> #include <ctime>
#include <algorithm> #include <algorithm>
@ -77,8 +78,6 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
class torrent; class torrent;
struct disk_io_job;
struct disk_interface;
struct torrent_peer; struct torrent_peer;
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
@ -765,7 +764,7 @@ namespace libtorrent
, time_point issue_time); , time_point issue_time);
void on_disk_write_complete(storage_error const& error void on_disk_write_complete(storage_error const& error
, peer_request r, std::shared_ptr<torrent> t); , peer_request r, std::shared_ptr<torrent> t);
void on_seed_mode_hashed(int status, int piece void on_seed_mode_hashed(int piece
, sha1_hash const& piece_hash, storage_error const& error); , sha1_hash const& piece_hash, storage_error const& error);
int request_timeout() const; int request_timeout() const;
void check_graceful_pause(); void check_graceful_pause();

View File

@ -101,7 +101,7 @@ POSSIBILITY OF SUCH DAMAGE.
// } // }
// virtual bool rename_file(int file, std::string const& new_name) // virtual bool rename_file(int file, std::string const& new_name)
// { assert(false); return false; } // { assert(false); return false; }
// virtual bool move_storage(std::string const& save_path) { return false; } // virtual status_t move_storage(std::string const& save_path) { return false; }
// virtual bool verify_resume_data(add_torrent_params const& rd // virtual bool verify_resume_data(add_torrent_params const& rd
// , std::vector<std::string> const* links // , std::vector<std::string> const* links
// , storage_error& error) { return false; } // , storage_error& error) { return false; }
@ -352,13 +352,7 @@ namespace libtorrent
// like ``release_files()``. // like ``release_files()``.
// //
//If an error occurs, ``storage_error`` should be set to reflect it. //If an error occurs, ``storage_error`` should be set to reflect it.
// virtual status_t move_storage(std::string const& save_path, int flags
// returns one of:
// | no_error = 0
// | fatal_disk_error = -1
// | need_full_check = -2
// | file_exist = -4
virtual int move_storage(std::string const& save_path, int flags
, storage_error& ec) = 0; , storage_error& ec) = 0;
// This function should verify the resume data ``rd`` with the files // This function should verify the resume data ``rd`` with the files
@ -500,7 +494,7 @@ namespace libtorrent
virtual void release_files(storage_error& ec) override; virtual void release_files(storage_error& ec) override;
virtual void delete_files(int options, storage_error& ec) override; virtual void delete_files(int options, storage_error& ec) override;
virtual void initialize(storage_error& ec) override; virtual void initialize(storage_error& ec) override;
virtual int move_storage(std::string const& save_path, int flags virtual status_t move_storage(std::string const& save_path, int flags
, storage_error& ec) override; , storage_error& ec) override;
virtual bool verify_resume_data(add_torrent_params const& rd virtual bool verify_resume_data(add_torrent_params const& rd
, std::vector<std::string> const& links , std::vector<std::string> const& links

View File

@ -67,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/linked_list.hpp" #include "libtorrent/linked_list.hpp"
#include "libtorrent/debug.hpp" #include "libtorrent/debug.hpp"
#include "libtorrent/piece_block.hpp" #include "libtorrent/piece_block.hpp"
#include "libtorrent/disk_interface.hpp" // for status_t
#include "libtorrent/aux_/file_progress.hpp" #include "libtorrent/aux_/file_progress.hpp"
#include "libtorrent/aux_/suggest_piece.hpp" #include "libtorrent/aux_/suggest_piece.hpp"
@ -350,9 +351,9 @@ namespace libtorrent
bt_peer_connection* find_peer(tcp::endpoint const& ep) const; bt_peer_connection* find_peer(tcp::endpoint const& ep) const;
peer_connection* find_peer(sha1_hash const& pid); peer_connection* find_peer(sha1_hash const& pid);
void on_resume_data_checked(int status, storage_error const& error); void on_resume_data_checked(status_t status, storage_error const& error);
void on_force_recheck(int status, storage_error const& error); void on_force_recheck(status_t status, storage_error const& error);
void on_piece_hashed(int status, int piece, sha1_hash const& piece_hash void on_piece_hashed(int piece, sha1_hash const& piece_hash
, storage_error const& error); , storage_error const& error);
void files_checked(); void files_checked();
void start_checking(); void start_checking();
@ -867,7 +868,7 @@ namespace libtorrent
void resume_download(); void resume_download();
void verify_piece(int piece); void verify_piece(int piece);
void on_piece_verified(int const status, int const piece void on_piece_verified(int const piece
, sha1_hash const& piece_hash, storage_error const& error); , sha1_hash const& piece_hash, storage_error const& error);
// this is called whenever a peer in this swarm becomes interesting // this is called whenever a peer in this swarm becomes interesting
@ -1116,7 +1117,7 @@ namespace libtorrent
void on_files_deleted(storage_error const& error); void on_files_deleted(storage_error const& error);
void on_torrent_paused(); void on_torrent_paused();
void on_storage_moved(int status, std::string const& path void on_storage_moved(status_t status, std::string const& path
, storage_error const& error); , storage_error const& error);
void on_file_renamed(std::string const& filename void on_file_renamed(std::string const& filename
, int const file_idx , int const file_idx

View File

@ -369,7 +369,7 @@ int block_cache::try_read(disk_io_job* j, bool expect_no_fail)
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
p->piece_log.push_back(piece_log_t(j->action, j->d.io.offset / 0x4000)); p->piece_log.push_back(piece_log_t(j->action, j->d.io.offset / 0x4000));
#endif #endif
cache_hit(p, j->requester, (j->flags & disk_io_job::volatile_read) != 0); cache_hit(p, j->requester, (j->flags & disk_interface::volatile_read) != 0);
ret = copy_from_piece(p, j, expect_no_fail); ret = copy_from_piece(p, j, expect_no_fail);
if (ret < 0) return ret; if (ret < 0) return ret;
@ -1269,7 +1269,7 @@ void block_cache::insert_blocks(cached_piece_entry* pe, int block, span<file::io
TORRENT_ASSERT(pe->in_use); TORRENT_ASSERT(pe->in_use);
TORRENT_PIECE_ASSERT(iov.size() > 0, pe); TORRENT_PIECE_ASSERT(iov.size() > 0, pe);
cache_hit(pe, j->requester, (j->flags & disk_io_job::volatile_read) != 0); cache_hit(pe, j->requester, (j->flags & disk_interface::volatile_read) != 0);
TORRENT_ASSERT(pe->in_use); TORRENT_ASSERT(pe->in_use);
@ -1304,7 +1304,7 @@ void block_cache::insert_blocks(cached_piece_entry* pe, int block, span<file::io
TORRENT_PIECE_ASSERT(pe->blocks[block].dirty == false, pe); TORRENT_PIECE_ASSERT(pe->blocks[block].dirty == false, pe);
++pe->num_blocks; ++pe->num_blocks;
++m_read_cache_size; ++m_read_cache_size;
if (j->flags & disk_io_job::volatile_read) ++m_volatile_size; if (j->flags & disk_interface::volatile_read) ++m_volatile_size;
if (flags & blocks_inc_refcount) if (flags & blocks_inc_refcount)
{ {

View File

@ -169,10 +169,10 @@ namespace libtorrent
error_code& ec; error_code& ec;
}; };
void on_hash(int const status, int const piece, sha1_hash const& piece_hash void on_hash(int const piece, sha1_hash const& piece_hash
, storage_error const& error, hash_state* st) , storage_error const& error, hash_state* st)
{ {
if (status != 0) if (error)
{ {
// on error // on error
st->ec = error.ec; st->ec = error.ec;
@ -185,8 +185,8 @@ namespace libtorrent
if (st->piece_counter < st->ct.num_pieces()) if (st->piece_counter < st->ct.num_pieces())
{ {
st->iothread.async_hash(st->storage.get(), st->piece_counter st->iothread.async_hash(st->storage.get(), st->piece_counter
, disk_io_job::sequential_access , disk_interface::sequential_access
, std::bind(&on_hash, _1, _2, _3, _4, st), nullptr); , std::bind(&on_hash, _1, _2, _3, st), nullptr);
++st->piece_counter; ++st->piece_counter;
} }
else else
@ -297,8 +297,8 @@ namespace libtorrent
hash_state st = { t, storage, disk_thread, 0, 0, f, ec }; hash_state st = { t, storage, disk_thread, 0, 0, f, ec };
for (int i = 0; i < piece_read_ahead; ++i) for (int i = 0; i < piece_read_ahead; ++i)
{ {
disk_thread.async_hash(storage.get(), i, disk_io_job::sequential_access disk_thread.async_hash(storage.get(), i, disk_interface::sequential_access
, std::bind(&on_hash, _1, _2, _3, _4, &st), nullptr); , std::bind(&on_hash, _1, _2, _3, &st), nullptr);
++st.piece_counter; ++st.piece_counter;
if (st.piece_counter >= t.num_pieces()) break; if (st.piece_counter >= t.num_pieces()) break;
} }

View File

@ -55,7 +55,7 @@ namespace libtorrent
void operator()(disk_io_job::hash_handler& h) const void operator()(disk_io_job::hash_handler& h) const
{ {
if (!h) return; if (!h) return;
h(m_job.ret, m_job.piece, sha1_hash(m_job.d.piece_hash), m_job.error); h(m_job.piece, sha1_hash(m_job.d.piece_hash), m_job.error);
} }
void operator()(disk_io_job::move_handler& h) const void operator()(disk_io_job::move_handler& h) const

View File

@ -119,11 +119,20 @@ namespace libtorrent
, bool const coalesce_buffers) , bool const coalesce_buffers)
{ {
int ret = 0; int ret = 0;
if (!(j->flags & disk_io_job::sequential_access)) ret |= file::random_access; if (!(j->flags & disk_interface::sequential_access)) ret |= file::random_access;
if (coalesce_buffers) ret |= file::coalesce_buffers; if (coalesce_buffers) ret |= file::coalesce_buffers;
return ret; return ret;
} }
// the do_* functions can return this to indicate the disk
// job did not complete immediately, and shouldn't be posted yet
constexpr status_t defer_handler = static_cast<status_t>(200);
// the job cannot be completed right now, put it back in the
// queue and try again later
constexpr status_t retry_job = static_cast<status_t>(201);
struct piece_refcount_holder struct piece_refcount_holder
{ {
explicit piece_refcount_holder(cached_piece_entry* p) : m_pe(p) explicit piece_refcount_holder(cached_piece_entry* p) : m_pe(p)
@ -705,7 +714,7 @@ namespace libtorrent
TORRENT_PIECE_ASSERT(j->piece == pe->piece, pe); TORRENT_PIECE_ASSERT(j->piece == pe->piece, pe);
if (j->completed(pe, block_size)) if (j->completed(pe, block_size))
{ {
j->ret = j->d.io.buffer_size; j->ret = status_t::no_error;
j->error = error; j->error = error;
completed_jobs.push_back(j); completed_jobs.push_back(j);
} }
@ -773,7 +782,7 @@ namespace libtorrent
{ {
disk_io_job* j = src.pop_front(); disk_io_job* j = src.pop_front();
TORRENT_ASSERT((j->flags & disk_io_job::in_progress) || !j->storage); TORRENT_ASSERT((j->flags & disk_io_job::in_progress) || !j->storage);
j->ret = disk_interface::fatal_disk_error; j->ret = status_t::fatal_disk_error;
j->error = e; j->error = e;
dst.push_back(j); dst.push_back(j);
} }
@ -1003,7 +1012,7 @@ namespace libtorrent
namespace { namespace {
typedef int (disk_io_thread::*disk_io_fun_t)(disk_io_job* j, jobqueue_t& completed_jobs); typedef status_t (disk_io_thread::*disk_io_fun_t)(disk_io_job* j, jobqueue_t& completed_jobs);
// this is a jump-table for disk I/O jobs // this is a jump-table for disk I/O jobs
const disk_io_fun_t job_functions[] = const disk_io_fun_t job_functions[] =
@ -1094,32 +1103,32 @@ namespace libtorrent
// call disk function // call disk function
// TODO: in the future, propagate exceptions back to the handlers // TODO: in the future, propagate exceptions back to the handlers
int ret = 0; status_t ret = status_t::no_error;
try try
{ {
ret = (this->*(job_functions[j->action]))(j, completed_jobs); ret = (this->*(job_functions[j->action]))(j, completed_jobs);
} }
catch (boost::system::system_error const& err) catch (boost::system::system_error const& err)
{ {
ret = disk_interface::fatal_disk_error; ret = status_t::fatal_disk_error;
j->error.ec = err.code(); j->error.ec = err.code();
j->error.operation = storage_error::exception; j->error.operation = storage_error::exception;
} }
catch (std::bad_alloc const&) catch (std::bad_alloc const&)
{ {
ret = disk_interface::fatal_disk_error; ret = status_t::fatal_disk_error;
j->error.ec = errors::no_memory; j->error.ec = errors::no_memory;
j->error.operation = storage_error::exception; j->error.operation = storage_error::exception;
} }
catch (std::exception const&) catch (std::exception const&)
{ {
ret = disk_interface::fatal_disk_error; ret = status_t::fatal_disk_error;
j->error.ec = boost::asio::error::fault; j->error.ec = boost::asio::error::fault;
j->error.operation = storage_error::exception; j->error.operation = storage_error::exception;
} }
// note that -2 errors are OK // note that -2 errors are OK
TORRENT_ASSERT(ret != disk_interface::fatal_disk_error TORRENT_ASSERT(ret != status_t::fatal_disk_error
|| (j->error.ec && j->error.operation != 0)); || (j->error.ec && j->error.operation != 0));
m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, -1); m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, -1);
@ -1172,14 +1181,14 @@ namespace libtorrent
completed_jobs.push_back(j); completed_jobs.push_back(j);
} }
int disk_io_thread::do_uncached_read(disk_io_job* j) status_t disk_io_thread::do_uncached_read(disk_io_job* j)
{ {
j->buffer.disk_block = m_disk_cache.allocate_buffer("send buffer"); j->buffer.disk_block = m_disk_cache.allocate_buffer("send buffer");
if (j->buffer.disk_block == nullptr) if (j->buffer.disk_block == nullptr)
{ {
j->error.ec = error::no_memory; j->error.ec = error::no_memory;
j->error.operation = storage_error::alloc_cache_piece; j->error.operation = storage_error::alloc_cache_piece;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
time_point start_time = clock_type::now(); time_point start_time = clock_type::now();
@ -1204,10 +1213,10 @@ namespace libtorrent
m_stats_counters.inc_stats_counter(counters::disk_read_time, read_time); m_stats_counters.inc_stats_counter(counters::disk_read_time, read_time);
m_stats_counters.inc_stats_counter(counters::disk_job_time, read_time); m_stats_counters.inc_stats_counter(counters::disk_job_time, read_time);
} }
return ret; return status_t::no_error;
} }
int disk_io_thread::do_read(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_read(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
int const block_size = m_disk_cache.block_size(); int const block_size = m_disk_cache.block_size();
int const piece_size = j->storage->files()->piece_size(j->piece); int const piece_size = j->storage->files()->piece_size(j->piece);
@ -1237,12 +1246,12 @@ namespace libtorrent
if (ret < 0) if (ret < 0)
{ {
ret = do_uncached_read(j); status_t const s = do_uncached_read(j);
std::unique_lock<std::mutex> l2(m_cache_mutex); std::unique_lock<std::mutex> l2(m_cache_mutex);
pe = m_disk_cache.find_piece(j); pe = m_disk_cache.find_piece(j);
if (pe) maybe_issue_queued_read_jobs(pe, completed_jobs); if (pe) maybe_issue_queued_read_jobs(pe, completed_jobs);
return ret; return s;
} }
// this is the offset that's aligned to block boundaries // this is the offset that's aligned to block boundaries
@ -1290,7 +1299,7 @@ namespace libtorrent
// the piece is supposed to be allocated when the // the piece is supposed to be allocated when the
// disk job is allocated // disk job is allocated
TORRENT_ASSERT_FAIL(); TORRENT_ASSERT_FAIL();
return ret; return status_t::fatal_disk_error;
} }
TORRENT_PIECE_ASSERT(pe->outstanding_read == 1, pe); TORRENT_PIECE_ASSERT(pe->outstanding_read == 1, pe);
@ -1302,7 +1311,7 @@ namespace libtorrent
pe->piece_log.push_back(piece_log_t(piece_log_t::clear_outstanding_jobs)); pe->piece_log.push_back(piece_log_t(piece_log_t::clear_outstanding_jobs));
#endif #endif
m_disk_cache.maybe_free_piece(pe); m_disk_cache.maybe_free_piece(pe);
return ret; return status_t::fatal_disk_error;
} }
int block = j->d.io.offset / block_size; int block = j->d.io.offset / block_size;
@ -1328,7 +1337,7 @@ namespace libtorrent
for (int i = 0; i < iov_len; ++i, ++block) for (int i = 0; i < iov_len; ++i, ++block)
m_disk_cache.dec_block_refcount(pe, block, block_cache::ref_reading); m_disk_cache.dec_block_refcount(pe, block, block_cache::ref_reading);
return j->d.io.buffer_size; return status_t::no_error;
} }
void disk_io_thread::maybe_issue_queued_read_jobs(cached_piece_entry* pe void disk_io_thread::maybe_issue_queued_read_jobs(cached_piece_entry* pe
@ -1373,13 +1382,13 @@ namespace libtorrent
m_stats_counters.inc_stats_counter(counters::num_blocks_cache_hits); m_stats_counters.inc_stats_counter(counters::num_blocks_cache_hits);
DLOG("do_read: cache hit\n"); DLOG("do_read: cache hit\n");
j->flags |= disk_interface::cache_hit; j->flags |= disk_interface::cache_hit;
j->ret = ret; j->ret = status_t::no_error;
completed_jobs.push_back(j); completed_jobs.push_back(j);
} }
else if (ret == -2) else if (ret == -2)
{ {
// error // error
j->ret = disk_io_job::operation_failed; j->ret = status_t::fatal_disk_error;
completed_jobs.push_back(j); completed_jobs.push_back(j);
} }
else else
@ -1413,7 +1422,7 @@ namespace libtorrent
} }
} }
int disk_io_thread::do_uncached_write(disk_io_job* j) status_t disk_io_thread::do_uncached_write(disk_io_job* j)
{ {
time_point start_time = clock_type::now(); time_point start_time = clock_type::now();
@ -1446,10 +1455,11 @@ namespace libtorrent
m_disk_cache.free_buffer(j->buffer.disk_block); m_disk_cache.free_buffer(j->buffer.disk_block);
j->buffer.disk_block = nullptr; j->buffer.disk_block = nullptr;
return ret; return ret != j->d.io.buffer_size
? status_t::fatal_disk_error : status_t::no_error;
} }
int disk_io_thread::do_write(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_write(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
TORRENT_ASSERT(j->d.io.buffer_size <= m_disk_cache.block_size()); TORRENT_ASSERT(j->d.io.buffer_size <= m_disk_cache.block_size());
@ -1465,7 +1475,7 @@ namespace libtorrent
TORRENT_ASSERT(pe->blocks[j->d.io.offset / 16 / 1024].buf != nullptr); TORRENT_ASSERT(pe->blocks[j->d.io.offset / 16 / 1024].buf != nullptr);
j->error.ec = error::operation_aborted; j->error.ec = error::operation_aborted;
j->error.operation = storage_error::write; j->error.operation = storage_error::write;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
pe = m_disk_cache.add_dirty_block(j); pe = m_disk_cache.add_dirty_block(j);
@ -1563,14 +1573,14 @@ namespace libtorrent
m_stats_counters.inc_stats_counter(counters::num_blocks_cache_hits); m_stats_counters.inc_stats_counter(counters::num_blocks_cache_hits);
DLOG("do_read: cache hit\n"); DLOG("do_read: cache hit\n");
j->flags |= disk_interface::cache_hit; j->flags |= disk_interface::cache_hit;
j->ret = ret; j->ret = status_t::no_error;
return 0; return 0;
} }
else if (ret == -2) else if (ret == -2)
{ {
j->error.ec = error::no_memory; j->error.ec = error::no_memory;
j->error.operation = storage_error::alloc_cache_piece; j->error.operation = storage_error::alloc_cache_piece;
j->ret = disk_io_job::operation_failed; j->ret = status_t::fatal_disk_error;
return 0; return 0;
} }
@ -1599,7 +1609,7 @@ namespace libtorrent
if (pe == nullptr) if (pe == nullptr)
{ {
j->ret = disk_interface::fatal_disk_error; j->ret = status_t::fatal_disk_error;
j->error.ec = error::no_memory; j->error.ec = error::no_memory;
j->error.operation = storage_error::read; j->error.operation = storage_error::read;
return 0; return 0;
@ -1723,7 +1733,7 @@ namespace libtorrent
} }
void disk_io_thread::async_hash(storage_interface* storage, int piece, std::uint8_t flags void disk_io_thread::async_hash(storage_interface* storage, int piece, std::uint8_t flags
, std::function<void(int, int, sha1_hash const&, storage_error const&)> handler, void* requester) , std::function<void(int, sha1_hash const&, storage_error const&)> handler, void* requester)
{ {
disk_io_job* j = allocate_job(disk_io_job::hash); disk_io_job* j = allocate_job(disk_io_job::hash);
j->storage = storage->shared_from_this(); j->storage = storage->shared_from_this();
@ -1761,7 +1771,7 @@ namespace libtorrent
} }
void disk_io_thread::async_move_storage(storage_interface* storage, std::string const& p, std::uint8_t const flags void disk_io_thread::async_move_storage(storage_interface* storage, std::string const& p, std::uint8_t const flags
, std::function<void(int, std::string const&, storage_error const&)> handler) , std::function<void(status_t, std::string const&, storage_error const&)> handler)
{ {
disk_io_job* j = allocate_job(disk_io_job::move_storage); disk_io_job* j = allocate_job(disk_io_job::move_storage);
j->storage = storage->shared_from_this(); j->storage = storage->shared_from_this();
@ -1831,7 +1841,7 @@ namespace libtorrent
void disk_io_thread::async_check_files(storage_interface* storage void disk_io_thread::async_check_files(storage_interface* storage
, add_torrent_params const* resume_data , add_torrent_params const* resume_data
, std::vector<std::string>& links , std::vector<std::string>& links
, std::function<void(int, storage_error const&)> handler) , std::function<void(status_t, storage_error const&)> handler)
{ {
std::vector<std::string>* links_vector std::vector<std::string>* links_vector
= new std::vector<std::string>(); = new std::vector<std::string>();
@ -2066,7 +2076,7 @@ namespace libtorrent
{ {
disk_io_job* hj = i.get(); disk_io_job* hj = i.get();
std::memcpy(hj->d.piece_hash, result.data(), 20); std::memcpy(hj->d.piece_hash, result.data(), 20);
hj->ret = 0; hj->ret = status_t::no_error;
} }
pe->hash.reset(); pe->hash.reset();
@ -2079,7 +2089,7 @@ namespace libtorrent
} }
} }
int disk_io_thread::do_uncached_hash(disk_io_job* j) status_t disk_io_thread::do_uncached_hash(disk_io_job* j)
{ {
// we're not using a cache. This is the simple path // we're not using a cache. This is the simple path
// just read straight from the file // just read straight from the file
@ -2127,10 +2137,10 @@ namespace libtorrent
sha1_hash piece_hash = h.final(); sha1_hash piece_hash = h.final();
std::memcpy(j->d.piece_hash, piece_hash.data(), 20); std::memcpy(j->d.piece_hash, piece_hash.data(), 20);
return ret >= 0 ? 0 : disk_interface::fatal_disk_error; return ret >= 0 ? status_t::no_error : status_t::fatal_disk_error;
} }
int disk_io_thread::do_hash(disk_io_job* j, jobqueue_t& /* completed_jobs */ ) status_t disk_io_thread::do_hash(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
{ {
int const piece_size = j->storage->files()->piece_size(j->piece); int const piece_size = j->storage->files()->piece_size(j->piece);
int const file_flags = file_flags_for_job(j int const file_flags = file_flags_for_job(j
@ -2145,7 +2155,7 @@ namespace libtorrent
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
pe->piece_log.push_back(piece_log_t(j->action)); pe->piece_log.push_back(piece_log_t(j->action));
#endif #endif
m_disk_cache.cache_hit(pe, j->requester, (j->flags & disk_io_job::volatile_read) != 0); m_disk_cache.cache_hit(pe, j->requester, (j->flags & disk_interface::volatile_read) != 0);
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1 || pe->cache_state == cached_piece_entry::read_lru2, pe); TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1 || pe->cache_state == cached_piece_entry::read_lru2, pe);
{ {
@ -2169,7 +2179,7 @@ namespace libtorrent
#endif #endif
m_disk_cache.update_cache_state(pe); m_disk_cache.update_cache_state(pe);
m_disk_cache.maybe_free_piece(pe); m_disk_cache.maybe_free_piece(pe);
return 0; return status_t::no_error;
} }
} }
else if (m_settings.get_bool(settings_pack::use_read_cache) == false) else if (m_settings.get_bool(settings_pack::use_read_cache) == false)
@ -2179,7 +2189,7 @@ namespace libtorrent
if (pe == nullptr) if (pe == nullptr)
{ {
std::uint16_t const cache_state = (j->flags & disk_io_job::volatile_read) std::uint16_t const cache_state = (j->flags & disk_interface::volatile_read)
? cached_piece_entry::volatile_read_lru ? cached_piece_entry::volatile_read_lru
: cached_piece_entry::read_lru1; : cached_piece_entry::read_lru1;
pe = m_disk_cache.allocate_piece(j, cache_state); pe = m_disk_cache.allocate_piece(j, cache_state);
@ -2188,7 +2198,7 @@ namespace libtorrent
{ {
j->error.ec = error::no_memory; j->error.ec = error::no_memory;
j->error.operation = storage_error::alloc_cache_piece; j->error.operation = storage_error::alloc_cache_piece;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
if (pe->hashing) if (pe->hashing)
@ -2251,7 +2261,7 @@ namespace libtorrent
l.unlock(); l.unlock();
int ret = 0; status_t ret = status_t::no_error;
int next_locked_block = 0; int next_locked_block = 0;
for (int i = offset / block_size; i < blocks_in_piece; ++i) for (int i = offset / block_size; i < blocks_in_piece; ++i)
{ {
@ -2287,7 +2297,7 @@ namespace libtorrent
j->error.ec = errors::no_memory; j->error.ec = errors::no_memory;
j->error.operation = storage_error::alloc_cache_piece; j->error.operation = storage_error::alloc_cache_piece;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
DLOG("do_hash: reading (piece: %d block: %d)\n", int(pe->piece), i); DLOG("do_hash: reading (piece: %d block: %d)\n", int(pe->piece), i);
@ -2295,11 +2305,12 @@ namespace libtorrent
time_point start_time = clock_type::now(); time_point start_time = clock_type::now();
TORRENT_PIECE_ASSERT(offset == i * block_size, pe); TORRENT_PIECE_ASSERT(offset == i * block_size, pe);
ret = j->storage->readv(iov, j->piece int read_ret = j->storage->readv(iov, j->piece
, offset, file_flags, j->error); , offset, file_flags, j->error);
if (ret < 0) if (read_ret < 0)
{ {
ret = status_t::fatal_disk_error;
TORRENT_ASSERT(j->error.ec && j->error.operation != 0); TORRENT_ASSERT(j->error.ec && j->error.operation != 0);
m_disk_cache.free_buffer(static_cast<char*>(iov.iov_base)); m_disk_cache.free_buffer(static_cast<char*>(iov.iov_base));
break; break;
@ -2308,9 +2319,9 @@ namespace libtorrent
// treat a short read as an error. The hash will be invalid, the // treat a short read as an error. The hash will be invalid, the
// block cannot be cached and the main thread should skip the rest // block cannot be cached and the main thread should skip the rest
// of this file // of this file
if (ret != iov.iov_len) if (read_ret != iov.iov_len)
{ {
ret = disk_interface::fatal_disk_error; ret = status_t::fatal_disk_error;
j->error.ec = boost::asio::error::eof; j->error.ec = boost::asio::error::eof;
j->error.operation = storage_error::read; j->error.operation = storage_error::read;
m_disk_cache.free_buffer(static_cast<char*>(iov.iov_base)); m_disk_cache.free_buffer(static_cast<char*>(iov.iov_base));
@ -2352,7 +2363,7 @@ namespace libtorrent
pe->hashing = 0; pe->hashing = 0;
if (ret >= 0) if (ret == status_t::no_error)
{ {
sha1_hash piece_hash = ph->h.final(); sha1_hash piece_hash = ph->h.final();
std::memcpy(j->d.piece_hash, piece_hash.data(), 20); std::memcpy(j->d.piece_hash, piece_hash.data(), 20);
@ -2368,12 +2379,12 @@ namespace libtorrent
m_disk_cache.maybe_free_piece(pe); m_disk_cache.maybe_free_piece(pe);
TORRENT_ASSERT(ret >= 0 || (j->error.ec && j->error.operation != 0)); TORRENT_ASSERT(ret == status_t::no_error || (j->error.ec && j->error.operation != 0));
return ret < 0 ? ret : 0; return ret;
} }
int disk_io_thread::do_move_storage(disk_io_job* j, jobqueue_t& /* completed_jobs */ ) status_t disk_io_thread::do_move_storage(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
{ {
// if this assert fails, something's wrong with the fence logic // if this assert fails, something's wrong with the fence logic
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
@ -2383,7 +2394,7 @@ namespace libtorrent
, j->flags, j->error); , j->flags, j->error);
} }
int disk_io_thread::do_release_files(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_release_files(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
// if this assert fails, something's wrong with the fence logic // if this assert fails, something's wrong with the fence logic
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
@ -2393,10 +2404,10 @@ namespace libtorrent
l.unlock(); l.unlock();
j->storage->release_files(j->error); j->storage->release_files(j->error);
return j->error ? disk_interface::fatal_disk_error : 0; return j->error ? status_t::fatal_disk_error : status_t::no_error;
} }
int disk_io_thread::do_delete_files(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_delete_files(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
TORRENT_ASSERT(j->buffer.delete_options != 0); TORRENT_ASSERT(j->buffer.delete_options != 0);
@ -2410,10 +2421,10 @@ namespace libtorrent
l.unlock(); l.unlock();
j->storage->delete_files(j->buffer.delete_options, j->error); j->storage->delete_files(j->buffer.delete_options, j->error);
return j->error ? disk_interface::fatal_disk_error : 0; return j->error ? status_t::fatal_disk_error : status_t::no_error;
} }
int disk_io_thread::do_check_fastresume(disk_io_job* j, jobqueue_t& /* completed_jobs */ ) status_t disk_io_thread::do_check_fastresume(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
{ {
// if this assert fails, something's wrong with the fence logic // if this assert fails, something's wrong with the fence logic
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
@ -2453,7 +2464,7 @@ namespace libtorrent
if (se) if (se)
{ {
j->error = se; j->error = se;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
if (has_files) if (has_files)
@ -2463,9 +2474,9 @@ namespace libtorrent
if (se) if (se)
{ {
j->error = se; j->error = se;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
return disk_interface::need_full_check; return status_t::need_full_check;
} }
} }
@ -2473,12 +2484,12 @@ namespace libtorrent
if (se) if (se)
{ {
j->error = se; j->error = se;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
return disk_interface::no_error; return status_t::no_error;
} }
int disk_io_thread::do_rename_file(disk_io_job* j, jobqueue_t& /* completed_jobs */ ) status_t disk_io_thread::do_rename_file(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
{ {
// if this assert fails, something's wrong with the fence logic // if this assert fails, something's wrong with the fence logic
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
@ -2486,10 +2497,10 @@ namespace libtorrent
// if files need to be closed, that's the storage's responsibility // if files need to be closed, that's the storage's responsibility
j->storage->rename_file(j->piece, j->buffer.string j->storage->rename_file(j->piece, j->buffer.string
, j->error); , j->error);
return j->error ? disk_interface::fatal_disk_error : disk_interface::no_error; return j->error ? status_t::fatal_disk_error : status_t::no_error;
} }
int disk_io_thread::do_stop_torrent(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_stop_torrent(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
// if this assert fails, something's wrong with the fence logic // if this assert fails, something's wrong with the fence logic
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
@ -2504,7 +2515,7 @@ namespace libtorrent
m_disk_cache.release_memory(); m_disk_cache.release_memory();
j->storage->release_files(j->error); j->storage->release_files(j->error);
return j->error ? disk_interface::fatal_disk_error : disk_interface::no_error; return j->error ? status_t::fatal_disk_error : status_t::no_error;
} }
namespace { namespace {
@ -2646,12 +2657,12 @@ namespace libtorrent
#endif #endif
} }
int disk_io_thread::do_flush_piece(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_flush_piece(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
std::unique_lock<std::mutex> l(m_cache_mutex); std::unique_lock<std::mutex> l(m_cache_mutex);
cached_piece_entry* pe = m_disk_cache.find_piece(j); cached_piece_entry* pe = m_disk_cache.find_piece(j);
if (pe == nullptr) return 0; if (pe == nullptr) return status_t::no_error;
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
pe->piece_log.push_back(piece_log_t(j->action)); pe->piece_log.push_back(piece_log_t(j->action));
@ -2659,23 +2670,23 @@ namespace libtorrent
try_flush_hashed(pe, m_settings.get_int( try_flush_hashed(pe, m_settings.get_int(
settings_pack::write_cache_line_size), completed_jobs, l); settings_pack::write_cache_line_size), completed_jobs, l);
return 0; return status_t::no_error;
} }
// this is triggered every time we insert a new dirty block in a piece // this is triggered every time we insert a new dirty block in a piece
// by the time this gets executed, the block may already have been flushed // by the time this gets executed, the block may already have been flushed
// triggered by another mechanism. // triggered by another mechanism.
int disk_io_thread::do_flush_hashed(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_flush_hashed(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
std::unique_lock<std::mutex> l(m_cache_mutex); std::unique_lock<std::mutex> l(m_cache_mutex);
cached_piece_entry* pe = m_disk_cache.find_piece(j); cached_piece_entry* pe = m_disk_cache.find_piece(j);
if (pe == nullptr) return 0; if (pe == nullptr) return status_t::no_error;
pe->outstanding_flush = 0; pe->outstanding_flush = 0;
if (pe->num_dirty == 0) return 0; if (pe->num_dirty == 0) return status_t::no_error;
// if multiple threads are flushing this piece, this assert may fire // if multiple threads are flushing this piece, this assert may fire
// this happens if the cache is running full and pieces are started to // this happens if the cache is running full and pieces are started to
@ -2717,38 +2728,38 @@ namespace libtorrent
m_disk_cache.maybe_free_piece(pe); m_disk_cache.maybe_free_piece(pe);
return 0; return status_t::no_error;
} }
int disk_io_thread::do_flush_storage(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_flush_storage(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
std::unique_lock<std::mutex> l(m_cache_mutex); std::unique_lock<std::mutex> l(m_cache_mutex);
flush_cache(j->storage.get(), flush_write_cache, completed_jobs, l); flush_cache(j->storage.get(), flush_write_cache, completed_jobs, l);
return 0; return status_t::no_error;
} }
int disk_io_thread::do_trim_cache(disk_io_job*, jobqueue_t& /* completed_jobs */) status_t disk_io_thread::do_trim_cache(disk_io_job*, jobqueue_t& /* completed_jobs */)
{ {
//#error implement //#error implement
return 0; return status_t::no_error;
} }
int disk_io_thread::do_file_priority(disk_io_job* j, jobqueue_t& /* completed_jobs */ ) status_t disk_io_thread::do_file_priority(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
{ {
std::unique_ptr<std::vector<std::uint8_t>> p(j->buffer.priorities); std::unique_ptr<std::vector<std::uint8_t>> p(j->buffer.priorities);
j->storage->set_file_priority(*p, j->error); j->storage->set_file_priority(*p, j->error);
return 0; return status_t::no_error;
} }
// this job won't return until all outstanding jobs on this // this job won't return until all outstanding jobs on this
// piece are completed or cancelled and the buffers for it // piece are completed or cancelled and the buffers for it
// have been evicted // have been evicted
int disk_io_thread::do_clear_piece(disk_io_job* j, jobqueue_t& completed_jobs) status_t disk_io_thread::do_clear_piece(disk_io_job* j, jobqueue_t& completed_jobs)
{ {
std::unique_lock<std::mutex> l(m_cache_mutex); std::unique_lock<std::mutex> l(m_cache_mutex);
cached_piece_entry* pe = m_disk_cache.find_piece(j); cached_piece_entry* pe = m_disk_cache.find_piece(j);
if (pe == nullptr) return 0; if (pe == nullptr) return status_t::no_error;
TORRENT_PIECE_ASSERT(pe->hashing == false, pe); TORRENT_PIECE_ASSERT(pe->hashing == false, pe);
pe->hashing_done = 0; pe->hashing_done = 0;
pe->hash.reset(); pe->hash.reset();
@ -2767,11 +2778,11 @@ namespace libtorrent
{ {
fail_jobs_impl(storage_error(boost::asio::error::operation_aborted) fail_jobs_impl(storage_error(boost::asio::error::operation_aborted)
, jobs, completed_jobs); , jobs, completed_jobs);
return 0; return status_t::no_error;
} }
m_disk_cache.mark_for_deletion(pe); m_disk_cache.mark_for_deletion(pe);
if (pe->num_blocks == 0) return 0; if (pe->num_blocks == 0) return status_t::no_error;
// we should always be able to evict the piece, since // we should always be able to evict the piece, since
// this is a fence job // this is a fence job

View File

@ -5110,7 +5110,7 @@ namespace libtorrent
// verified this piece (r.piece) // verified this piece (r.piece)
m_disk_thread.async_hash(&t->storage(), r.piece, 0 m_disk_thread.async_hash(&t->storage(), r.piece, 0
, std::bind(&peer_connection::on_seed_mode_hashed, self() , std::bind(&peer_connection::on_seed_mode_hashed, self()
, _1, _2, _3, _4), this); , _1, _2, _3), this);
t->verifying(r.piece); t->verifying(r.piece);
continue; continue;
} }
@ -5163,8 +5163,8 @@ namespace libtorrent
// this is called when a previously unchecked piece has been // this is called when a previously unchecked piece has been
// checked, while in seed-mode // checked, while in seed-mode
void peer_connection::on_seed_mode_hashed(int const void peer_connection::on_seed_mode_hashed(int const piece
, int const piece, sha1_hash const& piece_hash, storage_error const& error) , sha1_hash const& piece_hash, storage_error const& error)
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
INVARIANT_CHECK; INVARIANT_CHECK;

View File

@ -922,10 +922,10 @@ namespace libtorrent
return true; return true;
} }
int default_storage::move_storage(std::string const& sp, int const flags status_t default_storage::move_storage(std::string const& sp, int const flags
, storage_error& ec) , storage_error& ec)
{ {
int ret = disk_interface::no_error; status_t ret = status_t::no_error;
std::string const save_path = complete(sp); std::string const save_path = complete(sp);
// check to see if any of the files exist // check to see if any of the files exist
@ -950,7 +950,7 @@ namespace libtorrent
ec.ec = err; ec.ec = err;
ec.file = i; ec.file = i;
ec.operation = storage_error::stat; ec.operation = storage_error::stat;
return disk_interface::file_exist; return status_t::file_exist;
} }
} }
} }
@ -969,7 +969,7 @@ namespace libtorrent
ec.ec = err; ec.ec = err;
ec.file = -1; ec.file = -1;
ec.operation = storage_error::mkdir; ec.operation = storage_error::mkdir;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
} }
else if (err) else if (err)
@ -977,7 +977,7 @@ namespace libtorrent
ec.ec = err; ec.ec = err;
ec.file = -1; ec.file = -1;
ec.operation = storage_error::stat; ec.operation = storage_error::stat;
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
} }
@ -999,7 +999,7 @@ namespace libtorrent
if (flags == dont_replace && exists(new_path)) if (flags == dont_replace && exists(new_path))
{ {
if (ret == disk_interface::no_error) ret = disk_interface::need_full_check; if (ret == status_t::no_error) ret = status_t::need_full_check;
continue; continue;
} }
@ -1051,7 +1051,7 @@ namespace libtorrent
} }
} }
return disk_interface::fatal_disk_error; return status_t::fatal_disk_error;
} }
std::string const old_save_path = m_save_path; std::string const old_save_path = m_save_path;
@ -1363,7 +1363,7 @@ namespace libtorrent
void release_files(storage_error&) override {} void release_files(storage_error&) override {}
void delete_files(int, storage_error&) override {} void delete_files(int, storage_error&) override {}
void initialize(storage_error&) override {} void initialize(storage_error&) override {}
int move_storage(std::string const&, int, storage_error&) override { return 0; } status_t move_storage(std::string const&, int, storage_error&) override { return status_t::no_error; }
int readv(span<file::iovec_t const> bufs int readv(span<file::iovec_t const> bufs
, int, int, int, storage_error&) override , int, int, int, storage_error&) override
@ -1421,8 +1421,8 @@ namespace libtorrent
bool has_any_file(storage_error&) override { return false; } bool has_any_file(storage_error&) override { return false; }
void set_file_priority(std::vector<std::uint8_t> const& /* prio */ void set_file_priority(std::vector<std::uint8_t> const& /* prio */
, storage_error&) override {} , storage_error&) override {}
int move_storage(std::string const& /* save_path */ status_t move_storage(std::string const& /* save_path */
, int /* flags */, storage_error&) override { return 0; } , int /* flags */, storage_error&) override { return status_t::no_error; }
bool verify_resume_data(add_torrent_params const& /* rd */ bool verify_resume_data(add_torrent_params const& /* rd */
, std::vector<std::string> const& /* links */ , std::vector<std::string> const& /* links */
, storage_error&) override , storage_error&) override

View File

@ -1926,7 +1926,7 @@ namespace libtorrent
return nullptr; return nullptr;
} }
void torrent::on_resume_data_checked(int const status void torrent::on_resume_data_checked(status_t const status
, storage_error const& error) try , storage_error const& error) try
{ {
// hold a reference until this function returns // hold a reference until this function returns
@ -1946,7 +1946,7 @@ namespace libtorrent
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
if (status == disk_interface::fatal_disk_error) if (status == status_t::fatal_disk_error)
{ {
TORRENT_ASSERT(m_outstanding_check_files == false); TORRENT_ASSERT(m_outstanding_check_files == false);
m_add_torrent_params.reset(); m_add_torrent_params.reset();
@ -1991,7 +1991,7 @@ namespace libtorrent
// only report this error if the user actually provided resume data // only report this error if the user actually provided resume data
// (i.e. m_add_torrent_params->have_pieces) // (i.e. m_add_torrent_params->have_pieces)
if ((error || status != 0) if ((error || status != status_t::no_error)
&& m_add_torrent_params && m_add_torrent_params
&& !m_add_torrent_params->have_pieces.empty() && !m_add_torrent_params->have_pieces.empty()
&& m_ses.alerts().should_post<fastresume_rejected_alert>()) && m_ses.alerts().should_post<fastresume_rejected_alert>())
@ -2005,10 +2005,10 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) if (should_log())
{ {
if (status != 0) if (status != status_t::no_error)
{ {
debug_log("fastresume data rejected: ret: %d (%d) %s" debug_log("fastresume data rejected: ret: %d (%d) %s"
, status, error.ec.value(), error.ec.message().c_str()); , static_cast<int>(status), error.ec.value(), error.ec.message().c_str());
} }
else else
{ {
@ -2017,7 +2017,7 @@ namespace libtorrent
} }
#endif #endif
bool should_start_full_check = status != 0; bool should_start_full_check = status != status_t::no_error;
// if we got a partial pieces bitfield, it means we were in the middle of // if we got a partial pieces bitfield, it means we were in the middle of
// checking this torrent. pick it up where we left off // checking this torrent. pick it up where we left off
@ -2035,7 +2035,7 @@ namespace libtorrent
// that when the resume data check fails. For instance, if the resume data // that when the resume data check fails. For instance, if the resume data
// is incorrect, but we don't have any files, we skip the check and initialize // is incorrect, but we don't have any files, we skip the check and initialize
// the storage to not have anything. // the storage to not have anything.
if (status == 0) if (status == status_t::no_error)
{ {
// there are either no files for this torrent // there are either no files for this torrent
// or the resume_data was accepted // or the resume_data was accepted
@ -2190,7 +2190,7 @@ namespace libtorrent
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));
} }
void torrent::on_force_recheck(int const status, storage_error const& error) try void torrent::on_force_recheck(status_t const status, storage_error const& error) try
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
@ -2204,7 +2204,7 @@ namespace libtorrent
handle_disk_error("force_recheck", error); handle_disk_error("force_recheck", error);
return; return;
} }
if (status == 0) if (status == status_t::no_error)
{ {
// if there are no files, just start // if there are no files, just start
files_checked(); files_checked();
@ -2252,9 +2252,9 @@ namespace libtorrent
for (int i = 0; i < num_outstanding; ++i) for (int i = 0; i < num_outstanding; ++i)
{ {
m_ses.disk_thread().async_hash(m_storage.get(), m_checking_piece++ m_ses.disk_thread().async_hash(m_storage.get(), m_checking_piece++
, disk_io_job::sequential_access | disk_io_job::volatile_read , disk_interface::sequential_access | disk_interface::volatile_read
, std::bind(&torrent::on_piece_hashed , std::bind(&torrent::on_piece_hashed
, shared_from_this(), _1, _2, _3, _4), reinterpret_cast<void*>(1)); , shared_from_this(), _1, _2, _3), reinterpret_cast<void*>(1));
if (m_checking_piece >= m_torrent_file->num_pieces()) break; if (m_checking_piece >= m_torrent_file->num_pieces()) break;
} }
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
@ -2264,7 +2264,7 @@ namespace libtorrent
// This is only used for checking of torrents. i.e. force-recheck or initial checking // This is only used for checking of torrents. i.e. force-recheck or initial checking
// of existing files // of existing files
void torrent::on_piece_hashed(int const status, int const piece void torrent::on_piece_hashed(int const piece
, sha1_hash const& piece_hash, storage_error const& error) try , sha1_hash const& piece_hash, storage_error const& error) try
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
@ -2272,22 +2272,11 @@ namespace libtorrent
if (m_abort) return; if (m_abort) return;
if (status == disk_interface::disk_check_aborted)
{
m_checking_piece = 0;
m_num_checked_pieces = 0;
#ifndef TORRENT_DISABLE_LOGGING
debug_log("on_piece_hashed, disk_check_aborted");
#endif
pause();
return;
}
state_updated(); state_updated();
++m_num_checked_pieces; ++m_num_checked_pieces;
if (status < 0) if (error)
{ {
if (error.ec == boost::system::errc::no_such_file_or_directory if (error.ec == boost::system::errc::no_such_file_or_directory
|| error.ec == boost::asio::error::eof || error.ec == boost::asio::error::eof
@ -2383,9 +2372,9 @@ namespace libtorrent
} }
m_ses.disk_thread().async_hash(m_storage.get(), m_checking_piece++ m_ses.disk_thread().async_hash(m_storage.get(), m_checking_piece++
, disk_io_job::sequential_access | disk_io_job::volatile_read , disk_interface::sequential_access | disk_interface::volatile_read
, std::bind(&torrent::on_piece_hashed , std::bind(&torrent::on_piece_hashed
, shared_from_this(), _1, _2, _3, _4), reinterpret_cast<void*>(1)); , shared_from_this(), _1, _2, _3), reinterpret_cast<void*>(1));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
debug_log("on_piece_hashed, m_checking_piece: %d", m_checking_piece); debug_log("on_piece_hashed, m_checking_piece: %d", m_checking_piece);
#endif #endif
@ -3660,39 +3649,25 @@ namespace libtorrent
TORRENT_ASSERT(st.total_done >= st.total_wanted_done); TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
} }
void torrent::on_piece_verified(int const status, int const piece void torrent::on_piece_verified(int const piece
, sha1_hash const& piece_hash, storage_error const& error) try , sha1_hash const& piece_hash, storage_error const& error) try
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
if (m_abort) return; if (m_abort) return;
int ret = status; bool const passed = settings().get_bool(settings_pack::disable_hash_checks)
if (settings().get_bool(settings_pack::disable_hash_checks)) || (!error && sha1_hash(piece_hash) == m_torrent_file->hash_for_piece(piece));
{
ret = 0;
}
else if (ret == -1)
{
handle_disk_error("piece_verified", error);
}
else
{
if (sha1_hash(piece_hash) != m_torrent_file->hash_for_piece(piece))
ret = -2;
}
// 0: success, piece passed check bool const disk_error = !passed && error;
// -1: disk failure
// -2: piece failed check if (disk_error) handle_disk_error("piece_verified", error);
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) if (should_log())
{ {
debug_log("*** PIECE_FINISHED [ p: %d | chk: %s | size: %d ]" debug_log("*** PIECE_FINISHED [ p: %d | chk: %s | size: %d ]"
, piece, ((ret == 0) , piece, passed ? "passed" : disk_error ? "disk failed" : "failed"
?"passed":ret == -1
?"disk failed":"failed")
, m_torrent_file->piece_size(piece)); , m_torrent_file->piece_size(piece));
} }
#endif #endif
@ -3717,7 +3692,11 @@ namespace libtorrent
// it passed the check // it passed the check
if (!m_picker->is_piece_finished(piece)) return; if (!m_picker->is_piece_finished(piece)) return;
if (ret == 0) if (disk_error)
{
update_gauge();
}
else if (passed)
{ {
// the following call may cause picker to become invalid // the following call may cause picker to become invalid
// in case we just became a seed // in case we just became a seed
@ -3726,16 +3705,11 @@ namespace libtorrent
// mark it as verified // mark it as verified
if (m_seed_mode) verified(piece); if (m_seed_mode) verified(piece);
} }
else if (ret == -2) else
{ {
// piece_failed() will restore the piece // piece_failed() will restore the piece
piece_failed(piece); piece_failed(piece);
} }
else
{
TORRENT_ASSERT(ret == -1);
update_gauge();
}
} }
catch (...) { handle_exception(); } catch (...) { handle_exception(); }
@ -7778,20 +7752,20 @@ namespace libtorrent
} }
} }
void torrent::on_storage_moved(int const status, std::string const& path void torrent::on_storage_moved(status_t const status, std::string const& path
, storage_error const& error) try , storage_error const& error) try
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
m_moving_storage = false; m_moving_storage = false;
if (status == disk_interface::no_error if (status == status_t::no_error
|| status == disk_interface::need_full_check) || status == status_t::need_full_check)
{ {
if (alerts().should_post<storage_moved_alert>()) if (alerts().should_post<storage_moved_alert>())
alerts().emplace_alert<storage_moved_alert>(get_handle(), path); alerts().emplace_alert<storage_moved_alert>(get_handle(), path);
m_save_path = path; m_save_path = path;
set_need_save_resume(); set_need_save_resume();
if (status == disk_interface::need_full_check) if (status == status_t::need_full_check)
force_recheck(); force_recheck();
} }
else else
@ -10261,7 +10235,7 @@ namespace libtorrent
TORRENT_ASSERT(m_storage.get()); TORRENT_ASSERT(m_storage.get());
m_ses.disk_thread().async_hash(m_storage.get(), piece, 0 m_ses.disk_thread().async_hash(m_storage.get(), piece, 0
, std::bind(&torrent::on_piece_verified, shared_from_this(), _1, _2, _3, _4) , std::bind(&torrent::on_piece_verified, shared_from_this(), _1, _2, _3)
, reinterpret_cast<void*>(1)); , reinterpret_cast<void*>(1));
} }

View File

@ -62,8 +62,8 @@ struct test_storage_impl : storage_interface
bool has_any_file(storage_error& ec) override { return false; } bool has_any_file(storage_error& ec) override { return false; }
void set_file_priority(std::vector<std::uint8_t> const& prio void set_file_priority(std::vector<std::uint8_t> const& prio
, storage_error& ec) override {} , storage_error& ec) override {}
int move_storage(std::string const& save_path, int flags status_t move_storage(std::string const& save_path, int flags
, storage_error& ec) override { return 0; } , storage_error& ec) override { return status_t::no_error; }
bool verify_resume_data(add_torrent_params const& rd bool verify_resume_data(add_torrent_params const& rd
, std::vector<std::string> const& links , std::vector<std::string> const& links
, storage_error& ec) override { return true; } , storage_error& ec) override { return true; }

View File

@ -68,23 +68,24 @@ void on_read_piece(int ret, disk_io_job const& j, char const* data, int size)
if (ret > 0) TEST_CHECK(std::equal(j.buffer.disk_block, j.buffer.disk_block + ret, data)); if (ret > 0) TEST_CHECK(std::equal(j.buffer.disk_block, j.buffer.disk_block + ret, data));
} }
void on_check_resume_data(int const status, storage_error const& error, bool* done) void on_check_resume_data(status_t const status, storage_error const& error, bool* done)
{ {
std::cerr << time_now_string() << " on_check_resume_data ret: " << status; std::cerr << time_now_string() << " on_check_resume_data ret: "
<< static_cast<int>(status);
switch (status) switch (status)
{ {
case disk_interface::no_error: case status_t::no_error:
std::cerr << time_now_string() << " success" << std::endl; std::cerr << time_now_string() << " success" << std::endl;
break; break;
case disk_interface::fatal_disk_error: case status_t::fatal_disk_error:
std::cerr << time_now_string() << " disk error: " << error.ec.message() std::cerr << time_now_string() << " disk error: " << error.ec.message()
<< " file: " << error.file << std::endl; << " file: " << error.file << std::endl;
break; break;
case disk_interface::need_full_check: case status_t::need_full_check:
std::cerr << time_now_string() << " need full check" << std::endl; std::cerr << time_now_string() << " need full check" << std::endl;
break; break;
case disk_interface::disk_check_aborted: case status_t::file_exist:
std::cerr << time_now_string() << " aborted" << std::endl; std::cerr << time_now_string() << " file exist" << std::endl;
break; break;
} }
std::cerr << std::endl; std::cerr << std::endl;