added new alert when individual files complete

This commit is contained in:
Arvid Norberg 2009-07-04 04:58:24 +00:00
parent 52f39a9af0
commit 51992dda6a
9 changed files with 153 additions and 26 deletions

View File

@ -1,3 +1,4 @@
* added new alert when individual files complete
* added support for storing symbolic links in .torrent files
* added support for uTorrent interpretation of multi-tracker torrents
* handle torrents with duplicate filenames

View File

@ -1817,7 +1817,7 @@ Its declaration looks like this::
torrent_handle();
torrent_status status();
void file_progress(std::vector<size_type>& fp);
void file_progress(std::vector<size_type>& fp, int flags = 0);
void get_download_queue(std::vector<partial_piece_info>& queue) const;
void get_peer_info(std::vector<peer_info>& v) const;
torrent_info const& get_torrent_info() const;
@ -2029,7 +2029,7 @@ file_progress()
::
void file_progress(std::vector<size_type>& fp);
void file_progress(std::vector<size_type>& fp, int flags = 0);
This function fills in the supplied vector with the the number of bytes downloaded
of each file in this torrent. The progress values are ordered the same as the files
@ -2037,6 +2037,14 @@ in the `torrent_info`_. This operation is not very cheap. Its complexity is *O(n
Where *n* is the number of files, *m* is the number of downloading pieces and *j*
is the number of blocks in a piece.
The ``flags`` parameter can be used to specify the granularity of the file progress. If
left at the default value of 0, the progress will be as accurate as possible, but also
more expensive to calculate. If ``torrent_handle::piece_granularity`` is specified,
the progress will be specified in piece granularity. i.e. only pieces that have been
fully downloaded and passed the hash check count. When specifying piece granularity,
the operation is a lot cheaper, since libtorrent already keeps track of this internally
and no calculation is required.
save_path()
-----------
@ -4779,7 +4787,7 @@ generated and the torrent is paused.
};
file_renamed_alert
------------------------
------------------
This is posted as a response to a ``torrent_handle::rename_file`` call, if the rename
operation succeeds.
@ -5152,6 +5160,23 @@ This alert is generated when a block request receives a response.
};
file_completed_alert
--------------------
This is posted whenever an individual file completes its download. i.e.
All pieces overlapping this file have passed their hash check.
::
struct file_completed_alert: torrent_alert
{
// ...
int index;
};
The ``index`` member refers to the index of the file that completed.
block_downloading_alert
-----------------------

View File

@ -125,6 +125,30 @@ namespace libtorrent
int size;
};
struct TORRENT_EXPORT file_completed_alert: torrent_alert
{
file_completed_alert(torrent_handle const& h
, int index_)
: torrent_alert(h)
, index(index_)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new file_completed_alert(*this)); }
const static int static_category = alert::progress_notification;
virtual int category() const { return static_category; }
virtual char const* what() const { return "file completed"; }
virtual std::string message() const
{
char msg[200];
snprintf(msg, sizeof(msg), "%s: file %d finished downloading"
, torrent_alert::message().c_str(), index);
return msg;
}
int index;
};
struct TORRENT_EXPORT file_renamed_alert: torrent_alert
{
file_renamed_alert(torrent_handle const& h

View File

@ -270,7 +270,7 @@ namespace libtorrent
torrent_status status() const;
void file_progress(std::vector<size_type>& fp) const;
void file_progress(std::vector<size_type>& fp, int flags = 0) const;
void use_interface(const char* net_interface);
tcp::endpoint const& get_interface() const { return m_net_interface; }
@ -427,6 +427,10 @@ namespace libtorrent
return has_picker()?m_picker->have_piece(index):true;
}
// called when we learn that we have a piece
// only once per piece
void we_have(int index);
int num_have() const
{
return has_picker()
@ -838,6 +842,11 @@ namespace libtorrent
std::vector<boost::uint8_t> m_file_priority;
// this vector contains the number of bytes completely
// downloaded (as in passed-hash-check) in each file.
// this lets us trigger on individual files completing
std::vector<size_type> m_file_progress;
boost::scoped_ptr<piece_picker> m_picker;
std::vector<announce_entry> m_trackers;

View File

@ -371,7 +371,12 @@ namespace libtorrent
// the torrent_info.
void file_progress(std::vector<float>& progress) const TORRENT_DEPRECATED;
#endif
void file_progress(std::vector<size_type>& progress) const;
enum file_progress_flags_t
{
piece_granularity = 1
};
void file_progress(std::vector<size_type>& progress, int flags = 0) const;
void clear_error() const;

View File

@ -91,18 +91,6 @@ namespace libtorrent
m_files[index].path = new_filename;
}
file_storage::iterator file_storage::file_at_offset(size_type offset) const
{
// TODO: do a binary search
std::vector<file_entry>::const_iterator i;
for (i = begin(); i != end(); ++i)
{
if (i->offset <= offset && i->offset + i->size > offset)
return i;
}
return i;
}
namespace
{
bool compare_file_offset(file_entry const& lhs, file_entry const& rhs)
@ -111,6 +99,21 @@ namespace libtorrent
}
}
file_storage::iterator file_storage::file_at_offset(size_type offset) const
{
// find the file iterator and file offset
file_entry target;
target.offset = offset;
TORRENT_ASSERT(!compare_file_offset(target, m_files.front()));
std::vector<file_entry>::const_iterator file_iter = std::upper_bound(
begin(), end(), target, compare_file_offset);
TORRENT_ASSERT(file_iter != begin());
--file_iter;
return file_iter;
}
std::vector<file_slice> file_storage::map_block(int piece, size_type offset
, int size) const
{

View File

@ -238,6 +238,7 @@ namespace libtorrent
if (!m_seed_mode)
{
m_picker.reset(new piece_picker());
std::fill(m_file_progress.begin(), m_file_progress.end(), 0);
if (!m_resume_data.empty())
{
@ -599,6 +600,7 @@ namespace libtorrent
TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
m_file_priority.resize(m_torrent_file->num_files(), 1);
m_file_progress.resize(m_torrent_file->num_files(), 0);
m_block_size = (std::min)(m_block_size, m_torrent_file->piece_length());
@ -830,7 +832,7 @@ namespace libtorrent
char const* pieces_str = pieces->string_ptr();
for (int i = 0, end(pieces->string_length()); i < end; ++i)
{
if (pieces_str[i] & 1) m_picker->we_have(i);
if (pieces_str[i] & 1) we_have(i);
if (m_seed_mode && (pieces_str[i] & 2)) m_verified.set_bit(i);
}
}
@ -842,7 +844,7 @@ namespace libtorrent
for (int i = 0; i < slots->list_size(); ++i)
{
int piece = slots->list_int_value_at(i, -1);
if (piece >= 0) m_picker->we_have(piece);
if (piece >= 0) we_have(piece);
}
}
}
@ -931,6 +933,7 @@ namespace libtorrent
m_owning_storage->async_release_files();
if (!m_picker) m_picker.reset(new piece_picker());
std::fill(m_file_progress.begin(), m_file_progress.end(), 0);
m_picker->init(m_torrent_file->piece_length() / m_block_size
, int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
// assume that we don't have anything
@ -1014,7 +1017,7 @@ namespace libtorrent
TORRENT_ASSERT(m_picker);
if (j.offset >= 0 && !m_picker->have_piece(j.offset))
m_picker->we_have(j.offset);
we_have(j.offset);
// we're not done checking yet
// this handler will be called repeatedly until
@ -1789,6 +1792,48 @@ namespace libtorrent
m_picker->set_piece_priority(i, 6);
}
void torrent::we_have(int index)
{
// update m_file_progress
TORRENT_ASSERT(m_picker);
TORRENT_ASSERT(!have_piece(index));
std::cerr << "[" << this << "] GOT PIECE " << index << std::endl;
const int piece_size = m_torrent_file->piece_length();
size_type off = size_type(index) * piece_size;
file_storage::iterator f = m_torrent_file->files().file_at_offset(off);
int size = m_torrent_file->piece_size(index);
int file_index = f - m_torrent_file->files().begin();
for (; size > 0; ++f, ++file_index)
{
size_type file_offset = off - f->offset;
TORRENT_ASSERT(f != m_torrent_file->files().end());
TORRENT_ASSERT(file_offset < f->size);
int add = (std::min)(f->size - file_offset, (size_type)size);
m_file_progress[file_index] += add;
std::cerr << " adding " << add << " to " << file_index << std::endl;
TORRENT_ASSERT(m_file_progress[file_index]
<= m_torrent_file->files().at(file_index).size);
if (m_file_progress[file_index] >= m_torrent_file->files().at(file_index).size)
{
if (m_ses.m_alerts.should_post<piece_finished_alert>())
{
// this file just completed, post alert
m_ses.m_alerts.post_alert(file_completed_alert(get_handle()
, file_index));
}
}
size -= add;
off += add;
TORRENT_ASSERT(size >= 0);
}
m_picker->we_have(index);
}
void torrent::piece_passed(int index)
{
// INVARIANT_CHECK;
@ -1815,7 +1860,8 @@ namespace libtorrent
std::set<void*> peers;
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
m_picker->we_have(index);
we_have(index);
for (peer_iterator i = m_connections.begin(); i != m_connections.end();)
{
peer_connection* p = *i;
@ -4454,6 +4500,14 @@ namespace libtorrent
TORRENT_ASSERT((m_torrent_file->piece_length() & (m_block_size-1)) == 0);
}
// if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
for (std::vector<size_type>::const_iterator i = m_file_progress.begin()
, end(m_file_progress.end()); i != end; ++i)
{
int index = i - m_file_progress.begin();
TORRENT_ASSERT(*i <= m_torrent_file->files().at(index).size);
}
}
#endif
@ -5333,12 +5387,18 @@ namespace libtorrent
}
}
void torrent::file_progress(std::vector<size_type>& fp) const
void torrent::file_progress(std::vector<size_type>& fp, int flags) const
{
TORRENT_ASSERT(valid_metadata());
fp.resize(m_torrent_file->num_files(), 0);
if (flags & torrent_handle::piece_granularity)
{
std::copy(m_file_progress.begin(), m_file_progress.end(), fp.begin());
return;
}
if (is_seed())
{
for (int i = 0; i < m_torrent_file->num_files(); ++i)

View File

@ -378,10 +378,10 @@ namespace libtorrent
}
#endif
void torrent_handle::file_progress(std::vector<size_type>& progress) const
void torrent_handle::file_progress(std::vector<size_type>& progress, int flags) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(file_progress(progress));
TORRENT_FORWARD(file_progress(progress, flags));
}
torrent_status torrent_handle::status() const

View File

@ -71,8 +71,8 @@ void test_rate()
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
, true, false, true, "_transfer", 0, &t);
ses1.set_alert_mask(alert::all_categories & ~(alert::progress_notification | alert::performance_warning));
ses2.set_alert_mask(alert::all_categories & ~(alert::progress_notification | alert::performance_warning));
ses1.set_alert_mask(alert::all_categories & ~(alert::performance_warning));
ses2.set_alert_mask(alert::all_categories & ~(alert::performance_warning));
ptime start = time_now();