improve disk error handling
This commit is contained in:
parent
0283f07aed
commit
bd33814376
|
@ -73,6 +73,8 @@ namespace libtorrent
|
||||||
, piece(0)
|
, piece(0)
|
||||||
, offset(0)
|
, offset(0)
|
||||||
, priority(0)
|
, priority(0)
|
||||||
|
, error_piece(-1)
|
||||||
|
, error_op(-1)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
enum action_t
|
enum action_t
|
||||||
|
@ -123,6 +125,9 @@ namespace libtorrent
|
||||||
// the piece the error occurred on
|
// the piece the error occurred on
|
||||||
int error_piece;
|
int error_piece;
|
||||||
|
|
||||||
|
// the operation that failed (only read or write)
|
||||||
|
int error_op;
|
||||||
|
|
||||||
// this is called when operation completes
|
// this is called when operation completes
|
||||||
boost::function<void(int, disk_io_job const&)> callback;
|
boost::function<void(int, disk_io_job const&)> callback;
|
||||||
};
|
};
|
||||||
|
|
|
@ -275,7 +275,7 @@ namespace libtorrent
|
||||||
, piece_state_t s);
|
, piece_state_t s);
|
||||||
void mark_as_writing(piece_block block, void* peer);
|
void mark_as_writing(piece_block block, void* peer);
|
||||||
void mark_as_finished(piece_block block, void* peer);
|
void mark_as_finished(piece_block block, void* peer);
|
||||||
void write_failed(piece_block block);
|
void write_failed(int piece);
|
||||||
int num_peers(piece_block block) const;
|
int num_peers(piece_block block) const;
|
||||||
|
|
||||||
// returns information about the given piece
|
// returns information about the given piece
|
||||||
|
|
|
@ -290,6 +290,7 @@ namespace libtorrent
|
||||||
error_code const& error() const { return m_storage->error(); }
|
error_code const& error() const { return m_storage->error(); }
|
||||||
std::string const& error_file() const { return m_storage->error_file(); }
|
std::string const& error_file() const { return m_storage->error_file(); }
|
||||||
int last_piece() const { return m_last_piece; }
|
int last_piece() const { return m_last_piece; }
|
||||||
|
int last_operation() const { return m_last_op; }
|
||||||
void clear_error() { m_storage->clear_error(); }
|
void clear_error() { m_storage->clear_error(); }
|
||||||
|
|
||||||
int slot_for(int piece) const;
|
int slot_for(int piece) const;
|
||||||
|
@ -423,6 +424,9 @@ namespace libtorrent
|
||||||
// the last piece we wrote to or read from
|
// the last piece we wrote to or read from
|
||||||
int m_last_piece;
|
int m_last_piece;
|
||||||
|
|
||||||
|
// the last operation we did (read or write)
|
||||||
|
int m_last_op;
|
||||||
|
|
||||||
// this is saved in case we need to instantiate a new
|
// this is saved in case we need to instantiate a new
|
||||||
// storage (osed when remapping files)
|
// storage (osed when remapping files)
|
||||||
storage_constructor_type m_storage_constructor;
|
storage_constructor_type m_storage_constructor;
|
||||||
|
|
|
@ -216,6 +216,7 @@ namespace libtorrent
|
||||||
|
|
||||||
void ip_filter_updated() { m_policy.ip_filter_updated(); }
|
void ip_filter_updated() { m_policy.ip_filter_updated(); }
|
||||||
|
|
||||||
|
void handle_disk_error(disk_io_job const& j, peer_connection* c = 0);
|
||||||
void clear_error();
|
void clear_error();
|
||||||
void set_error(error_code const& ec, std::string const& file);
|
void set_error(error_code const& ec, std::string const& file);
|
||||||
bool has_error() const { return m_error; }
|
bool has_error() const { return m_error; }
|
||||||
|
|
|
@ -1249,9 +1249,12 @@ namespace libtorrent
|
||||||
j.error = ec;
|
j.error = ec;
|
||||||
j.error_file = j.storage->error_file();
|
j.error_file = j.storage->error_file();
|
||||||
j.error_piece = j.storage->last_piece();
|
j.error_piece = j.storage->last_piece();
|
||||||
|
j.error_op = j.storage->last_operation();
|
||||||
j.storage->clear_error();
|
j.storage->clear_error();
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
std::cout << "ERROR: '" << j.str << "' " << j.error_file << std::endl;
|
std::cout << "ERROR: '" << j.str << "' while "
|
||||||
|
<< (j.error_op == disk_io_job::read?"reading ":"writing ")
|
||||||
|
<< j.error_file << std::endl;
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1406,11 +1409,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
case disk_io_job::read_and_hash:
|
case disk_io_job::read_and_hash:
|
||||||
{
|
{
|
||||||
if (test_error(j))
|
|
||||||
{
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
m_log << log_time() << " read_and_hash " << j.buffer_size << std::endl;
|
m_log << log_time() << " read_and_hash " << j.buffer_size << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1421,8 +1419,10 @@ namespace libtorrent
|
||||||
if (j.buffer == 0)
|
if (j.buffer == 0)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
j.error = error_code(ENOMEM, get_posix_category());
|
j.error = error_code(boost::system::errc::not_enough_memory
|
||||||
j.error_piece = -1;
|
, get_posix_category());
|
||||||
|
j.error_piece = j.piece;
|
||||||
|
j.error_op = disk_io_job::read;
|
||||||
j.str = j.error.message();
|
j.str = j.error.message();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1450,6 +1450,7 @@ namespace libtorrent
|
||||||
j.error = error_code(errors::failed_hash_check, libtorrent_category);
|
j.error = error_code(errors::failed_hash_check, libtorrent_category);
|
||||||
j.str = j.error.message();
|
j.str = j.error.message();
|
||||||
j.error_piece = j.storage->last_piece();
|
j.error_piece = j.storage->last_piece();
|
||||||
|
j.error_op = disk_io_job::read;
|
||||||
j.buffer = 0;
|
j.buffer = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1478,8 +1479,10 @@ namespace libtorrent
|
||||||
if (j.buffer == 0)
|
if (j.buffer == 0)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
j.error = error_code(ENOMEM, get_posix_category());
|
j.error = error_code(boost::system::errc::not_enough_memory
|
||||||
j.error_piece = -1;
|
, get_posix_category());
|
||||||
|
j.error_piece = j.piece;
|
||||||
|
j.error_op = disk_io_job::read;
|
||||||
j.str = j.error.message();
|
j.str = j.error.message();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1513,6 +1516,7 @@ namespace libtorrent
|
||||||
j.error_file.clear();
|
j.error_file.clear();
|
||||||
j.str = j.error.message();
|
j.str = j.error.message();
|
||||||
j.error_piece = j.storage->last_piece();
|
j.error_piece = j.storage->last_piece();
|
||||||
|
j.error_op = disk_io_job::read;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2078,18 +2078,14 @@ namespace libtorrent
|
||||||
|
|
||||||
if (ret == -1 || !t)
|
if (ret == -1 || !t)
|
||||||
{
|
{
|
||||||
if (t->has_picker()) t->picker().write_failed(block_finished);
|
|
||||||
|
|
||||||
if (!t)
|
if (!t)
|
||||||
{
|
{
|
||||||
disconnect(j.str.c_str());
|
disconnect(j.str.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->alerts().should_post<file_error_alert>())
|
// handle_disk_error may disconnect us
|
||||||
t->alerts().post_alert(file_error_alert(j.error_file, t->get_handle(), j.str));
|
t->handle_disk_error(j, this);
|
||||||
t->set_error(j.error, j.error_file);
|
|
||||||
t->pause();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3530,10 +3526,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (t->alerts().should_post<file_error_alert>())
|
// handle_disk_error may disconnect us
|
||||||
t->alerts().post_alert(file_error_alert(j.error_file, t->get_handle(), j.str));
|
t->handle_disk_error(j, this);
|
||||||
t->set_error(j.error, j.error_file);
|
|
||||||
t->pause();
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2117,20 +2117,15 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::write_failed(piece_block block)
|
void piece_picker::write_failed(int piece)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
|
||||||
std::vector<downloading_piece>::iterator i
|
std::vector<downloading_piece>::iterator i
|
||||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(piece));
|
||||||
TORRENT_ASSERT(i != m_downloads.end());
|
TORRENT_ASSERT(i != m_downloads.end());
|
||||||
block_info& info = i->info[block.block_index];
|
|
||||||
TORRENT_ASSERT(info.state == block_info::state_writing);
|
|
||||||
TORRENT_ASSERT(info.num_peers == 0);
|
|
||||||
|
|
||||||
--i->writing;
|
erase_download_piece(i);
|
||||||
info.state = block_info::state_none;
|
|
||||||
info.peer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::mark_as_finished(piece_block block, void* peer)
|
void piece_picker::mark_as_finished(piece_block block, void* peer)
|
||||||
|
|
|
@ -481,6 +481,7 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(!error());
|
TORRENT_ASSERT(!error());
|
||||||
int num_read = 0;
|
int num_read = 0;
|
||||||
int slot_size = piece_size - ph.offset;
|
int slot_size = piece_size - ph.offset;
|
||||||
|
m_last_op = disk_io_job::read;
|
||||||
if (slot_size > 0)
|
if (slot_size > 0)
|
||||||
{
|
{
|
||||||
int block_size = 16 * 1024;
|
int block_size = 16 * 1024;
|
||||||
|
@ -1485,6 +1486,7 @@ ret:
|
||||||
, m_scratch_buffer2(io, 0)
|
, m_scratch_buffer2(io, 0)
|
||||||
, m_scratch_piece(-1)
|
, m_scratch_piece(-1)
|
||||||
, m_last_piece(-1)
|
, m_last_piece(-1)
|
||||||
|
, m_last_op(-1)
|
||||||
, m_storage_constructor(sc)
|
, m_storage_constructor(sc)
|
||||||
, m_io_thread(io)
|
, m_io_thread(io)
|
||||||
, m_torrent(torrent)
|
, m_torrent(torrent)
|
||||||
|
@ -1747,6 +1749,7 @@ ret:
|
||||||
TORRENT_ASSERT(offset >= 0);
|
TORRENT_ASSERT(offset >= 0);
|
||||||
TORRENT_ASSERT(num_bufs > 0);
|
TORRENT_ASSERT(num_bufs > 0);
|
||||||
m_last_piece = piece_index;
|
m_last_piece = piece_index;
|
||||||
|
m_last_op = disk_io_job::read;
|
||||||
int slot = slot_for(piece_index);
|
int slot = slot_for(piece_index);
|
||||||
return m_storage->readv(bufs, slot, offset, num_bufs);
|
return m_storage->readv(bufs, slot, offset, num_bufs);
|
||||||
}
|
}
|
||||||
|
@ -1767,6 +1770,7 @@ ret:
|
||||||
file::iovec_t* iov = TORRENT_ALLOCA(file::iovec_t, num_bufs);
|
file::iovec_t* iov = TORRENT_ALLOCA(file::iovec_t, num_bufs);
|
||||||
std::copy(bufs, bufs + num_bufs, iov);
|
std::copy(bufs, bufs + num_bufs, iov);
|
||||||
m_last_piece = piece_index;
|
m_last_piece = piece_index;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
int slot = allocate_slot_for_piece(piece_index);
|
int slot = allocate_slot_for_piece(piece_index);
|
||||||
int ret = m_storage->writev(bufs, slot, offset, num_bufs);
|
int ret = m_storage->writev(bufs, slot, offset, num_bufs);
|
||||||
// only save the partial hash if the write succeeds
|
// only save the partial hash if the write succeeds
|
||||||
|
@ -2340,6 +2344,7 @@ ret:
|
||||||
// the slot where this piece belongs is
|
// the slot where this piece belongs is
|
||||||
// free. Just move the piece there.
|
// free. Just move the piece there.
|
||||||
m_last_piece = piece;
|
m_last_piece = piece;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
m_storage->move_slot(m_current_slot, piece);
|
m_storage->move_slot(m_current_slot, piece);
|
||||||
if (m_storage->error()) return -1;
|
if (m_storage->error()) return -1;
|
||||||
|
|
||||||
|
@ -2567,6 +2572,7 @@ ret:
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
m_last_piece = piece_index;
|
m_last_piece = piece_index;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
if (other_piece >= 0)
|
if (other_piece >= 0)
|
||||||
ret |= m_storage->swap_slots(other_slot, m_current_slot);
|
ret |= m_storage->swap_slots(other_slot, m_current_slot);
|
||||||
else
|
else
|
||||||
|
@ -2606,6 +2612,7 @@ ret:
|
||||||
|
|
||||||
}
|
}
|
||||||
m_last_piece = other_piece;
|
m_last_piece = other_piece;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
if (ret) return skip_file();
|
if (ret) return skip_file();
|
||||||
|
|
||||||
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|
||||||
|
@ -2645,6 +2652,7 @@ ret:
|
||||||
TORRENT_ASSERT(piece_index == slot1);
|
TORRENT_ASSERT(piece_index == slot1);
|
||||||
|
|
||||||
m_last_piece = piece_index;
|
m_last_piece = piece_index;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
m_storage->swap_slots(m_current_slot, slot1);
|
m_storage->swap_slots(m_current_slot, slot1);
|
||||||
|
|
||||||
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|
||||||
|
@ -2692,6 +2700,7 @@ ret:
|
||||||
}
|
}
|
||||||
|
|
||||||
m_last_piece = piece_index;
|
m_last_piece = piece_index;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
if (ret) return skip_file();
|
if (ret) return skip_file();
|
||||||
|
|
||||||
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|
||||||
|
@ -2838,6 +2847,7 @@ ret:
|
||||||
, m_piece_to_slot[piece_at_our_slot]);
|
, m_piece_to_slot[piece_at_our_slot]);
|
||||||
|
|
||||||
m_last_piece = piece_index;
|
m_last_piece = piece_index;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
m_storage->move_slot(piece_index, slot_index);
|
m_storage->move_slot(piece_index, slot_index);
|
||||||
|
|
||||||
TORRENT_ASSERT(m_slot_to_piece[piece_index] == piece_index);
|
TORRENT_ASSERT(m_slot_to_piece[piece_index] == piece_index);
|
||||||
|
@ -2882,6 +2892,7 @@ ret:
|
||||||
if (m_piece_to_slot[pos] != has_no_slot)
|
if (m_piece_to_slot[pos] != has_no_slot)
|
||||||
{
|
{
|
||||||
m_last_piece = pos;
|
m_last_piece = pos;
|
||||||
|
m_last_op = disk_io_job::write;
|
||||||
new_free_slot = m_piece_to_slot[pos];
|
new_free_slot = m_piece_to_slot[pos];
|
||||||
m_storage->move_slot(new_free_slot, pos);
|
m_storage->move_slot(new_free_slot, pos);
|
||||||
m_slot_to_piece[pos] = pos;
|
m_slot_to_piece[pos] = pos;
|
||||||
|
|
|
@ -340,6 +340,42 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent::handle_disk_error(disk_io_job const& j, peer_connection* c)
|
||||||
|
{
|
||||||
|
if (!j.error) return;
|
||||||
|
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
|
(*m_ses.m_logger) << "disk error: '" << j.str << "' while "
|
||||||
|
<< (j.error_op == disk_io_job::read?"reading ":"writing ")
|
||||||
|
<< " piece " << j.error_piece << " in file " << j.error_file << "\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (j.error == error_code(boost::system::errc::not_enough_memory, get_posix_category()))
|
||||||
|
{
|
||||||
|
if (alerts().should_post<file_error_alert>())
|
||||||
|
alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
|
||||||
|
if (c) c->disconnect("no memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_ASSERT(j.error_piece >= 0);
|
||||||
|
|
||||||
|
if (j.error_op == disk_io_job::write)
|
||||||
|
{
|
||||||
|
// we failed to write j.error_piece to disk
|
||||||
|
// tell the piece picker
|
||||||
|
if (has_picker() && j.error_piece >= 0) picker().write_failed(j.error_piece);
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify the user of the error
|
||||||
|
if (alerts().should_post<file_error_alert>())
|
||||||
|
alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
|
||||||
|
|
||||||
|
// put the torrent in an error-state
|
||||||
|
set_error(j.error, j.error_file);
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r, read_piece_struct* rp)
|
void torrent::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r, read_piece_struct* rp)
|
||||||
{
|
{
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
@ -350,8 +386,7 @@ namespace libtorrent
|
||||||
if (ret != r.length)
|
if (ret != r.length)
|
||||||
{
|
{
|
||||||
rp->fail = true;
|
rp->fail = true;
|
||||||
set_error(j.error, j.error_file);
|
handle_disk_error(j);
|
||||||
pause();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -428,11 +463,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
if (has_picker()) picker().write_failed(block_finished);
|
handle_disk_error(j);
|
||||||
if (alerts().should_post<file_error_alert>())
|
|
||||||
alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
|
|
||||||
set_error(j.error, j.error_file);
|
|
||||||
pause();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
picker().mark_as_finished(block_finished, 0);
|
picker().mark_as_finished(block_finished, 0);
|
||||||
|
|
Loading…
Reference in New Issue