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).
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);