From f63702c964cbdd8cf4d742a66baa443c9ee1c458 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 16 Oct 2005 16:58:41 +0000 Subject: [PATCH] optimized session::add_torrent() by putting more info in torrent_info, to make it possible to reproduce the exact info section from an torrent_info object. The result is that the .torrent file is only parsed once. --- ChangeLog | 7 +-- Jamfile | 2 - docs/manual.html | 12 ++--- docs/manual.rst | 12 ++--- examples/client_test.cpp | 13 ++++-- examples/dump_torrent.cpp | 6 +-- examples/simple_client.cpp | 2 +- include/libtorrent/session.hpp | 15 ++++++- include/libtorrent/torrent.hpp | 6 +-- include/libtorrent/torrent_info.hpp | 12 ++++- src/piece_picker.cpp | 6 +-- src/session.cpp | 10 ++--- src/torrent.cpp | 16 +++---- src/torrent_handle.cpp | 3 +- src/torrent_info.cpp | 69 ++++++++++++++++++++--------- 15 files changed, 117 insertions(+), 74 deletions(-) diff --git a/ChangeLog b/ChangeLog index fdc3b7038..fec9e0b21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,11 @@ - * greatly improved the command line control of the example client_test - * fixed bug where upload rate limit was not being applied + * changed the interface to session::add_torrent for soem speed optimizations. + * greatly improved the command line control of the example client_test. + * fixed bug where upload rate limit was not being applied. * files that are being checked will no longer stall files that don't need checking. * changed the way libtorrent identifies support for its excentions to look for 'ext' at the end of the peer-id. - * improved performance by adding a circle buffer for the send buffer + * improved performance by adding a circle buffer for the send buffer. * fixed bugs in the http tracker connection when using an http proxy. * fixed problem with storage's file pool when creating torrents and then starting to seed them. diff --git a/Jamfile b/Jamfile index ba51f78af..575e141f9 100755 --- a/Jamfile +++ b/Jamfile @@ -36,7 +36,6 @@ project torrent multi msvc:/Zc:wchar_t msvc:/Zc:forScope - TORRENT_PROFILE : usage-requirements @@ -44,7 +43,6 @@ project torrent $(BOOST_ROOT) release:NDEBUG BOOST_ALL_NO_LIB - TORRENT_PROFILE ; diff --git a/docs/manual.html b/docs/manual.html index 119605632..3580d35e2 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -555,7 +555,7 @@ class session: public boost::noncopyable , const char* listen_interface = 0); torrent_handle add_torrent( - entry const& e + torrent_info const& ti , boost::filesystem::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true @@ -630,7 +630,7 @@ timeout can be set with set_http_
 torrent_handle add_torrent(
-        entry const& e
+        torrent_info const& ti
         , boost::filesystem::path const& save_path
         , entry const& resume_data = entry()
         , bool compact_mode = true
@@ -667,10 +667,10 @@ size is an even power of 2, so must the block size be. If the block size given h
 out to be greater than the piece size, it will simply be clamped to the piece size.

The torrent_handle returned by add_torrent() can be used to retrieve information about the torrent's progress, its peers etc. It is also used to abort a torrent.

-

The second overload that takes a tracker url and an info-hash instead of metadata (entry) -can be used with torrents where (at least some) peers support the metadata extension. For -the overload to be available, libtorrent must be built with extensions enabled -(TORRENT_ENABLE_EXTENSIONS defined).

+

The second overload that takes a tracker url and an info-hash instead of metadata +(torrent_info) can be used with torrents where (at least some) peers support +the metadata extension. For the overload to be available, libtorrent must be built +with extensions enabled (TORRENT_ENABLE_EXTENSIONS defined).

remove_torrent()

diff --git a/docs/manual.rst b/docs/manual.rst index 2a817c051..d793172a3 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -433,7 +433,7 @@ The ``session`` class has the following synopsis:: , const char* listen_interface = 0); torrent_handle add_torrent( - entry const& e + torrent_info const& ti , boost::filesystem::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true @@ -512,7 +512,7 @@ add_torrent() :: torrent_handle add_torrent( - entry const& e + torrent_info const& ti , boost::filesystem::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true @@ -554,10 +554,10 @@ out to be greater than the piece size, it will simply be clamped to the piece si The torrent_handle_ returned by ``add_torrent()`` can be used to retrieve information about the torrent's progress, its peers etc. It is also used to abort a torrent. -The second overload that takes a tracker url and an info-hash instead of metadata (``entry``) -can be used with torrents where (at least some) peers support the metadata extension. For -the overload to be available, libtorrent must be built with extensions enabled -(``TORRENT_ENABLE_EXTENSIONS`` defined). +The second overload that takes a tracker url and an info-hash instead of metadata +(``torrent_info``) can be used with torrents where (at least some) peers support +the metadata extension. For the overload to be available, libtorrent must be built +with extensions enabled (``TORRENT_ENABLE_EXTENSIONS`` defined). remove_torrent() ---------------- diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 19f4d49ba..c695a07ec 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -242,7 +242,7 @@ void print_peer_info(std::ostream& out, std::vector const { using namespace libtorrent; - out << " down up q r flags block progress client \n"; + out << " down (total) up (total) q r flags block progress client \n"; for (std::vector::const_iterator i = peers.begin(); i != peers.end(); ++i) @@ -289,7 +289,7 @@ void add_torrent(libtorrent::session& ses in.unsetf(std::ios_base::skipws); entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); torrent_info t(e); - TORRENT_CHECKPOINT("-- load torrent"); + std::cout << t.name() << "\n"; TORRENT_CHECKPOINT("++ load resumedata"); @@ -306,12 +306,17 @@ void add_torrent(libtorrent::session& ses } catch (invalid_encoding&) {} catch (boost::filesystem::filesystem_error&) {} - TORRENT_CHECKPOINT("-- load resumedata"); - handles.push_back(ses.add_torrent(e, save_path, resume_data, true, 16 * 1024)); + TORRENT_CHECKPOINT("++ ses::add_torrent"); + + handles.push_back(ses.add_torrent(t, save_path, resume_data, true, 16 * 1024)); + TORRENT_CHECKPOINT("-- ses::add_torrent"); + handles.back().set_max_connections(60); handles.back().set_max_uploads(-1); handles.back().set_ratio(preferred_ratio); + + TORRENT_CHECKPOINT("-- add_torrent"); } int main(int ac, char* av[]) diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index eee20475c..d3bd47f80 100755 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -58,20 +58,16 @@ int main(int argc, char* argv[]) in.unsetf(std::ios_base::skipws); entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); - - std::cout << "\n\n----- raw info -----\n\n"; e.print(std::cout); - torrent_info t(e); // print info about torrent std::cout << "\n\n----- torrent file info -----\n\n"; std::cout << "trackers:\n"; for (std::vector::const_iterator i = t.trackers().begin(); - i != t.trackers().end(); - ++i) + i != t.trackers().end(); ++i) { std::cout << i->tier << ": " << i->url << "\n"; } diff --git a/examples/simple_client.cpp b/examples/simple_client.cpp index aed24de65..985b16e57 100755 --- a/examples/simple_client.cpp +++ b/examples/simple_client.cpp @@ -65,7 +65,7 @@ int main(int argc, char* argv[]) std::ifstream in(argv[1], std::ios_base::binary); in.unsetf(std::ios_base::skipws); entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); - s.add_torrent(e, "./"); + s.add_torrent(torrent_info(e), "./"); // wait for the user to end char a; diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index e08d63cec..908502228 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -54,7 +54,6 @@ POSSIBILITY OF SUCH DAMAGE. #endif #include "libtorrent/torrent_handle.hpp" -//#include "libtorrent/torrent.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/socket.hpp" @@ -317,12 +316,24 @@ namespace libtorrent // all torrent_handles must be destructed before the session is destructed! torrent_handle add_torrent( - entry const& metadata + torrent_info const& ti , boost::filesystem::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true , int block_size = 16 * 1024); + // TODO: depricated, this is for backwards compatibility only + torrent_handle add_torrent( + entry const& e + , boost::filesystem::path const& save_path + , entry const& resume_data = entry() + , bool compact_mode = true + , int block_size = 16 * 1024) + { + return add_torrent(torrent_info(e), save_path, resume_data + , compact_mode, block_size); + } + torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index ab3931665..3ee490dc7 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -97,7 +97,6 @@ namespace libtorrent torrent( detail::session_impl& ses , detail::checker_impl& checker - , entry const& metadata , torrent_info const& tf , boost::filesystem::path const& save_path , address const& net_interface @@ -386,7 +385,7 @@ namespace libtorrent bool valid_metadata() const { return m_storage.get() != 0 && m_connections_initialized; } - std::vector const& metadata() const { return m_metadata; } + std::vector const& metadata() const; bool received_metadata( char const* buf @@ -524,7 +523,8 @@ namespace libtorrent // this buffer is filled with the info-section of // the metadata file while downloading it from // peers, and while sending it. - std::vector m_metadata; + // it is mutable because it's generated lazily + mutable std::vector m_metadata; // this is a bitfield of size 256, each bit represents // a piece of the metadata. It is set to one if we diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 0e09ac082..7d0d7192c 100755 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -91,7 +91,7 @@ namespace libtorrent torrent_info(entry const& torrent_file); ~torrent_info(); - entry create_torrent(); + entry create_torrent() const; entry create_info_metadata() const; void set_comment(char const* str); void set_creator(char const* str); @@ -168,7 +168,9 @@ namespace libtorrent size_type m_total_size; // the hash that identifies this torrent - sha1_hash m_info_hash; + // it is mutable because it's calculated + // lazily + mutable sha1_hash m_info_hash; std::string m_name; @@ -191,6 +193,12 @@ namespace libtorrent // or not. e.g. test/test there's one file and one directory // and they have the same name. bool m_multifile; + + // contains any non-parsed entries from the info-section + // these are kept in order to be able to accurately + // reproduce the info-section when sending the metadata + // to peers. + entry m_extra_info; }; } diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 35e21dd2e..6d7b78998 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -651,9 +651,9 @@ namespace libtorrent assert(num_blocks > 0); #ifdef TORRENT_VERBOSE_LOGGING - std::ofstream f("piece_picker.log", std::ios_base::app); - f << "backup_blocks: " << backup_blocks.size() << "\n" - << "used: " << std::min(num_blocks, (int)backup_blocks.size()) << "\n----\n"; +// std::ofstream f("piece_picker.log", std::ios_base::app); +// f << "backup_blocks: " << backup_blocks.size() << "\n" +// << "used: " << std::min(num_blocks, (int)backup_blocks.size()) << "\n----\n"; #endif interesting_blocks.insert(interesting_blocks.end() diff --git a/src/session.cpp b/src/session.cpp index 633acb61b..720087fbe 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -382,6 +382,9 @@ namespace libtorrent { namespace detail { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) m_logger = create_log("main_session", false); + using boost::posix_time::second_clock; + using boost::posix_time::to_simple_string; + (*m_logger) << to_simple_string(second_clock::universal_time()) << "\n"; #endif std::fill(m_extension_enabled, m_extension_enabled + peer_connection::num_supported_extensions, true); @@ -1142,13 +1145,12 @@ namespace libtorrent // current platform. // if the torrent already exists, this will throw duplicate_torrent torrent_handle session::add_torrent( - entry const& metadata + torrent_info const& ti , boost::filesystem::path const& save_path , entry const& resume_data , bool compact_mode , int block_size) { - TORRENT_CHECKPOINT("++ session::add_torrent()"); // make sure the block_size is an even power of 2 #ifndef NDEBUG for (int i = 0; i < 32; ++i) @@ -1163,7 +1165,6 @@ namespace libtorrent assert(!save_path.empty()); - torrent_info ti(metadata); if (ti.begin_files() == ti.end_files()) throw std::runtime_error("no files in torrent"); @@ -1184,7 +1185,7 @@ namespace libtorrent // the checker thread and store it before starting // the thread boost::shared_ptr torrent_ptr( - new torrent(m_impl, m_checker_impl, metadata, ti, save_path + new torrent(m_impl, m_checker_impl, ti, save_path , m_impl.m_listen_interface, compact_mode, block_size)); boost::shared_ptr d( @@ -1200,7 +1201,6 @@ namespace libtorrent // job in its queue m_checker_impl.m_cond.notify_one(); - TORRENT_CHECKPOINT("-- session::add_torrent()"); return torrent_handle(&m_impl, &m_checker_impl, ti.info_hash()); } diff --git a/src/torrent.cpp b/src/torrent.cpp index e2d630f94..fb302f595 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -182,7 +182,6 @@ namespace libtorrent torrent::torrent( detail::session_impl& ses , detail::checker_impl& checker - , entry const& metadata , torrent_info const& tf , boost::filesystem::path const& save_path , address const& net_interface @@ -246,7 +245,6 @@ namespace libtorrent m_ul_bandwidth_quota.min = 100; m_ul_bandwidth_quota.max = resource_request::inf; - if (m_ses.m_upload_rate == -1) { m_ul_bandwidth_quota.given = resource_request::inf; @@ -256,13 +254,7 @@ namespace libtorrent m_ul_bandwidth_quota.given = 400; } - m_policy.reset(new policy(this)); - // if anything should be optimized in this constructor - // this encoding should be made on demand. But that would - // require the copying of the entry-tree instead, which - // probably is more expensive - bencode(std::back_inserter(m_metadata), metadata["info"]); init(); } @@ -1340,6 +1332,14 @@ namespace libtorrent return m_tracker_address; } + std::vector const& torrent::metadata() const + { + if (m_metadata.empty()) + bencode(std::back_inserter(m_metadata), m_torrent_file.create_torrent()); + assert(!m_metadata.empty()); + return m_metadata; + } + torrent_status torrent::status() const { assert(std::accumulate( diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 44b6160eb..e9041ecbd 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -436,8 +436,7 @@ namespace libtorrent entry::list_type& peer_list = ret["peers"].list(); for (torrent::const_peer_iterator i = t->begin(); - i != t->end(); - ++i) + i != t->end(); ++i) { // we cannot save remote connection // since we don't know their listen port diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 55da94dc7..8bec12dd0 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -124,6 +124,7 @@ namespace libtorrent torrent_info::torrent_info(const entry& torrent_file) : m_creation_date(date(not_a_date_time)) , m_multifile(false) + , m_extra_info(entry::dictionary_t) { try { @@ -146,6 +147,7 @@ namespace libtorrent , m_name() , m_creation_date(second_clock::universal_time()) , m_multifile(false) + , m_extra_info(entry::dictionary_t) { } @@ -156,6 +158,7 @@ namespace libtorrent , m_name() , m_creation_date(second_clock::universal_time()) , m_multifile(false) + , m_extra_info(entry::dictionary_t) { } @@ -251,6 +254,24 @@ namespace libtorrent hash_string.begin() + i*20 , hash_string.begin() + (i+1)*20 , m_piece_hash[i].begin()); + + for (entry::dictionary_type::const_iterator i = info.dict().begin() + , end(info.dict().end()); i != end; ++i) + { + if (i->first == "pieces" + || i->first == "piece length" + || i->first == "length") + continue; + m_extra_info[i->first] = i->second; + } + +#ifndef NDEBUG + std::vector info_section_buf; + entry gen_info_section = create_info_metadata(); + bencode(std::back_inserter(info_section_buf), gen_info_section); + assert(hasher(&info_section_buf[0], info_section_buf.size()).final() + == m_info_hash); +#endif } // extracts information from a libtorrent file and fills in the structures in @@ -405,35 +426,40 @@ namespace libtorrent // you have to add files to the torrent first assert(!m_files.empty()); - entry info(entry::dictionary_t); + entry info(m_extra_info); + + if (!info.find_key("name")) + info["name"] = m_name; - info["name"] = m_name; if (!m_multifile) { info["length"] = m_files.front().size; } else { - entry& files = info["files"]; - files = entry(entry::list_t); - - for (std::vector::const_iterator i = m_files.begin(); - i != m_files.end(); ++i) + if (!info.find_key("files")) { - files.list().push_back(entry(entry::dictionary_t)); - entry& file_e = files.list().back(); - file_e["length"] = i->size; - entry& path_e = file_e["path"]; - path_e = entry(entry::list_t); + entry& files = info["files"]; + files = entry(entry::list_t); - fs::path const& file_path(i->path); - assert(file_path.has_branch_path()); - assert(*file_path.begin() == m_name); - - for (fs::path::iterator j = boost::next(file_path.begin()); - j != file_path.end(); ++j) + for (std::vector::const_iterator i = m_files.begin(); + i != m_files.end(); ++i) { - path_e.list().push_back(*j); + files.list().push_back(entry(entry::dictionary_t)); + entry& file_e = files.list().back(); + file_e["length"] = i->size; + entry& path_e = file_e["path"]; + path_e = entry(entry::list_t); + + fs::path const& file_path(i->path); + assert(file_path.has_branch_path()); + assert(*file_path.begin() == m_name); + + for (fs::path::iterator j = boost::next(file_path.begin()); + j != file_path.end(); ++j) + { + path_e.list().push_back(*j); + } } } } @@ -445,8 +471,7 @@ namespace libtorrent std::string& p = pieces.string(); for (std::vector::const_iterator i = m_piece_hash.begin(); - i != m_piece_hash.end(); - ++i) + i != m_piece_hash.end(); ++i) { p.append((char*)i->begin(), (char*)i->end()); } @@ -454,7 +479,7 @@ namespace libtorrent return info; } - entry torrent_info::create_torrent() + entry torrent_info::create_torrent() const { assert(m_piece_length > 0);