From d06f125513a65d33e51891398659bc66a1e01688 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 9 Jul 2008 10:45:07 +0000 Subject: [PATCH] improved accuracy of the file progress report to include completed blocks from incomplete pieces (but not partial blocks) --- examples/client_test.cpp | 2 +- include/libtorrent/file_storage.hpp | 1 + include/libtorrent/torrent_info.hpp | 2 ++ src/file_storage.cpp | 14 +++++++++- src/torrent.cpp | 41 +++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 3621221d6..e9fe80206 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1412,7 +1412,7 @@ int main(int ac, char* av[]) out << progress_bar(file_progress[i], 60, "32"); else out << progress_bar(file_progress[i], 60, "33"); - out << " " << to_string(file_progress[i] * 100.f, 3) << "% " + out << " " << to_string(file_progress[i] * 100.f, 5) << "% " << info.file_at(i).path.leaf() << "\n"; } diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index bbb606bf6..47fcb92eb 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -94,6 +94,7 @@ namespace libtorrent typedef std::vector::const_iterator iterator; typedef std::vector::const_reverse_iterator reverse_iterator; + iterator file_at_offset(size_type offset) const; iterator begin() const { return m_files.begin(); } iterator end() const { return m_files.end(); } reverse_iterator rbegin() const { return m_files.rbegin(); } diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 0cc9b93b2..6c87b475a 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -118,6 +118,8 @@ namespace libtorrent int num_files() const { return m_files.num_files(); } file_entry const& file_at(int index) const { return m_files.at(index); } + file_iterator file_at_offset(size_type offset) const + { return m_files.file_at_offset(offset); } std::vector map_block(int piece, size_type offset, int size) const { return m_files.map_block(piece, offset, size); } peer_request map_file(int file, size_type offset, int size) const diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 69e88d25d..e5b544dc3 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -64,6 +64,18 @@ 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::const_iterator i; + for (i = begin(); i != end(); ++i) + { + if (i->offset < offset && i->offset + i->size > offset) + return i; + } + return i; + } + std::vector file_storage::map_block(int piece, size_type offset , int size_) const { @@ -75,7 +87,7 @@ namespace libtorrent TORRENT_ASSERT(start + size <= m_total_size); // find the file iterator and file offset - // TODO: make a vector that can map piece -> file index in O(1) + // TODO: do a binary search on the file offsets size_type file_offset = start; std::vector::const_iterator file_iter; diff --git a/src/torrent.cpp b/src/torrent.cpp index c062a5db6..38d7113cb 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3982,6 +3982,7 @@ namespace libtorrent return; } + TORRENT_ASSERT(has_picker()); fp.resize(m_torrent_file->num_files(), 0.f); for (int i = 0; i < m_torrent_file->num_files(); ++i) @@ -4011,6 +4012,46 @@ namespace libtorrent fp[i] = static_cast(done) / m_torrent_file->files().at(i).size; } + + const std::vector& q + = m_picker->get_download_queue(); + + for (std::vector::const_iterator + i = q.begin(), end(q.end()); i != end; ++i) + { + size_type offset = size_type(i->index) * m_torrent_file->piece_length(); + torrent_info::file_iterator file = m_torrent_file->file_at_offset(offset); + int file_index = file - m_torrent_file->begin_files(); + int num_blocks = m_picker->blocks_in_piece(i->index); + piece_picker::block_info const* info = i->info; + for (int k = 0; k < num_blocks; ++k) + { + if (info[k].state != piece_picker::block_info::state_writing + && info[k].state != piece_picker::block_info::state_finished) + continue; + if (offset + m_block_size > file->offset + file->size) + { + // split the block on multiple files + size_type block_size = m_block_size; + while (offset + block_size > file->offset + file->size) + { + TORRENT_ASSERT(offset < file->offset + file->size); + size_type slice = file->offset + file->size - offset; + fp[file_index] += float(slice) / file->size; + offset += slice; + block_size -= slice; + ++file; + ++file_index; + if (file == m_torrent_file->end_files()) break; + } + } + else + { + fp[file_index] += float(m_block_size) / file->size; + offset += m_block_size; + } + } + } } void torrent::set_state(torrent_status::state_t s)