diff --git a/ChangeLog b/ChangeLog index 423d91665..9c62d8c2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * optimize copying torrent_info and file_storage objects * cancel non-critical DNS lookups when shutting down, to cut down on shutdown delay. * greatly simplify the debug logging infrastructure. logs are now delivered diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index 311f6eca9..04eb6d39d 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -534,6 +534,10 @@ namespace libtorrent boost::int64_t file_offset(internal_file_entry const& fe) const TORRENT_DEPRECATED; #endif + // if the backing buffer changed for this storage, this is the pointer + // offset to add to any pointers to make them point into the new buffer + void apply_pointer_offset(ptrdiff_t off); + private: // the number of bytes in a regular piece @@ -590,7 +594,6 @@ namespace libtorrent // the number of files. This is used when // the torrent is unloaded int m_num_files; - }; } diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 3cc8951d7..d0f1e2e6d 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -156,7 +156,10 @@ namespace libtorrent , name(0) , path_index(fe.path_index) { - set_name(fe.filename().c_str()); + if (fe.name_len == name_is_owned) + name = allocate_string_copy(fe.name); + else + name = fe.name; } internal_file_entry& internal_file_entry::operator=(internal_file_entry const& fe) @@ -211,6 +214,21 @@ namespace libtorrent return name ? name : ""; } + void file_storage::apply_pointer_offset(ptrdiff_t off) + { + for (int i = 0; i < m_files.size(); ++i) + { + if (m_files[i].name_len == internal_file_entry::name_is_owned) continue; + m_files[i].name += off; + } + + for (int i = 0; i < m_file_hashes.size(); ++i) + { + if (m_file_hashes[i] == NULL) continue; + m_file_hashes[i] += off; + } + } + #if TORRENT_USE_WSTRING #ifndef TORRENT_NO_DEPRECATE void file_storage::set_name(std::wstring const& n) diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index d59a7f154..7e3e2c2ac 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -697,28 +697,31 @@ namespace libtorrent #if TORRENT_USE_INVARIANT_CHECKS t.check_invariant(); #endif - if (m_info_section_size > 0) - { - error_code ec; - m_info_section.reset(new char[m_info_section_size]); - memcpy(m_info_section.get(), t.m_info_section.get(), m_info_section_size); + if (m_info_section_size == 0) return; + + error_code ec; + m_info_section.reset(new char[m_info_section_size]); + memcpy(m_info_section.get(), t.m_info_section.get(), m_info_section_size); + + ptrdiff_t offset = m_info_section.get() - t.m_info_section.get(); + + m_files.apply_pointer_offset(offset); + if (m_orig_files) + const_cast(*m_orig_files).apply_pointer_offset(offset); + #if TORRENT_USE_ASSERTS || !defined BOOST_NO_EXCEPTIONS - int ret = + int ret = #endif - lazy_bdecode(m_info_section.get(), m_info_section.get() - + m_info_section_size, m_info_dict, ec); + lazy_bdecode(m_info_section.get(), m_info_section.get() + + m_info_section_size, m_info_dict, ec); #ifndef BOOST_NO_EXCEPTIONS - if (ret != 0) throw libtorrent_exception(ec); + if (ret != 0) throw libtorrent_exception(ec); #endif - TORRENT_ASSERT(ret == 0); + TORRENT_ASSERT(ret == 0); - ptrdiff_t offset = m_info_section.get() - t.m_info_section.get(); - - m_piece_hashes += offset; - TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); - TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); - } - INVARIANT_CHECK; + m_piece_hashes += offset; + TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); + TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); } void torrent_info::resolve_duplicate_filenames() diff --git a/test/Makefile.am b/test/Makefile.am index dcbd7c86a..d8ba2ef51 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -113,6 +113,7 @@ EXTRA_DIST = Jamfile \ test_torrents/invalid_file_size.torrent \ test_torrents/empty_path_multi.torrent \ test_torrents/duplicate_web_seeds.torrent \ + test_torrents/sample.torrent \ eztv.xml \ kat.xml \ cb.xml \ diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index f3c81fc43..3f217033d 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -34,12 +34,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_storage.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/create_torrent.hpp" +#include using namespace libtorrent; -int test_main() +void test_storage() { - file_storage fs; fs.add_file("test/temporary.txt", 0x4000); @@ -90,6 +90,53 @@ int test_main() fprintf(stderr, "%s == %s\n", p.c_str(), filenames[i]); TEST_CHECK(p == filenames[i]); } +} + +void test_copy() +{ + boost::shared_ptr a(boost::make_shared( + libtorrent::combine_path("..", libtorrent::combine_path("test_torrents", "sample.torrent")))); + + boost::shared_ptr b(boost::make_shared(*a)); + + // clear out the buffer for a, just to make sure b doesn't have any + // references into it by mistake + int s = a->metadata_size(); + memset(a->metadata().get(), 0, s); + + a.reset(); + + TEST_EQUAL(b->num_files(), 3); + + char const* expected_files[] = + { + "sample/text_file2.txt", + "sample/.____padding_file/0", + "sample/text_file.txt", + }; + + sha1_hash file_hashes[] = + { + sha1_hash(0), + sha1_hash(0), + sha1_hash("abababababababababab") + }; + + for (int i = 0; i < b->num_files(); ++i) + { + std::string p = b->file_at(i).path; + convert_path_to_posix(p); + TEST_EQUAL(p, expected_files[i]); + fprintf(stderr, "%s\n", p.c_str()); + + TEST_EQUAL(b->files().hash(i), file_hashes[i]); + } +} + +int test_main() +{ + test_storage(); + test_copy(); return 0; } diff --git a/test/test_torrents/sample.torrent b/test/test_torrents/sample.torrent new file mode 100644 index 000000000..2793361f9 Binary files /dev/null and b/test/test_torrents/sample.torrent differ diff --git a/test/web_seed_suite.cpp b/test/web_seed_suite.cpp index 7315d4930..8896747a3 100644 --- a/test/web_seed_suite.cpp +++ b/test/web_seed_suite.cpp @@ -317,8 +317,7 @@ int EXPORT run_http_suite(int proxy, char const* protocol, bool test_url_seed // generate a torrent with pad files to make sure they // are not requested web seeds - libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize - | libtorrent::create_torrent::calculate_file_hashes); + libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize); char tmp[512]; if (test_url_seed)