From b7b542f587df8099829dfe4047687fcbeb21372a Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 23 Aug 2010 08:48:02 +0000 Subject: [PATCH] optimized file_pool lookups and string handling --- examples/client_test.cpp | 18 ++++++++++++++++-- examples/connection_tester.cpp | 5 ++++- include/libtorrent/file.hpp | 5 ++--- include/libtorrent/file_pool.hpp | 16 ++++++++++------ include/libtorrent/file_storage.hpp | 12 +++++++++--- src/file_pool.cpp | 29 ++++++++++++++++------------- src/file_storage.cpp | 2 ++ src/storage.cpp | 28 ++++++++++++++-------------- 8 files changed, 73 insertions(+), 42 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 112449e8d..6af7f3b27 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -60,6 +60,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file.hpp" #include "libtorrent/peer_info.hpp" #include "libtorrent/socket_io.hpp" // print_address +#include "libtorrent/time.hpp" using boost::bind; @@ -130,16 +131,29 @@ bool sleep_and_input(char* c, int sleep) // sets the terminal to single-character mode // and resets when destructed set_keypress s; - + libtorrent::ptime start = libtorrent::time_now_hires(); + int ret = 0; +retry: fd_set set; FD_ZERO(&set); FD_SET(0, &set); timeval tv = {sleep, 0}; - if (select(1, &set, 0, 0, &tv) > 0) + ret = select(1, &set, 0, 0, &tv); + if (ret > 0) { *c = getc(stdin); return true; } + if (errno == EINTR) + { + if (total_milliseconds(libtorrent::time_now_hires() - start) < sleep * 1000) + goto retry; + return false; + } + + if (ret < 0 && errno != 0 && errno != ETIMEDOUT) + fprintf(stderr, "select failed: %s\n", strerror(errno)); + libtorrent::sleep(500); return false; } diff --git a/examples/connection_tester.cpp b/examples/connection_tester.cpp index 72fe92533..34ec70054 100644 --- a/examples/connection_tester.cpp +++ b/examples/connection_tester.cpp @@ -52,7 +52,9 @@ struct peer_conn : s(ios) , read_pos(0) , state(handshaking) - , pieces(num_pieces) + // don't request anything from the last piece + // to keep things simple + , pieces(num_pieces - 1) , block(0) , blocks_per_piece(blocks_pp) , info_hash(ih) @@ -248,6 +250,7 @@ int main(int argc, char const* argv[]) conns.push_back(new peer_conn(ios, ti.num_pieces(), ti.piece_length() / 16 / 1024 , ep, (char const*)&ti.info_hash()[0])); libtorrent::sleep(1); + ios.poll_one(); } ios.run(); diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index 4cbab5c73..fc64a3f61 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/error_code.hpp" #include "libtorrent/size_type.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" #ifdef TORRENT_WINDOWS // windows part @@ -164,10 +165,8 @@ namespace libtorrent bool m_done; }; - class TORRENT_EXPORT file: public boost::noncopyable + struct TORRENT_EXPORT file: boost::noncopyable, intrusive_ptr_base { - public: - enum { // when a file is opened with no_buffer diff --git a/include/libtorrent/file_pool.hpp b/include/libtorrent/file_pool.hpp index 0e1a6aae2..84ba43aef 100644 --- a/include/libtorrent/file_pool.hpp +++ b/include/libtorrent/file_pool.hpp @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #pragma warning(push, 1) #endif -#include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -50,14 +50,16 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + struct file_entry; + struct TORRENT_EXPORT file_pool : boost::noncopyable { file_pool(int size = 40): m_size(size), m_low_prio_io(true) {} - boost::shared_ptr open_file(void* st, std::string const& p - , int m, error_code& ec); + boost::intrusive_ptr open_file(void* st, std::string const& p + , file_entry const& fe, int m, error_code& ec); void release(void* st); - void release(std::string const& p); + void release(void* st, file_entry const& fe); void resize(int size); int size_limit() const { return m_size; } void set_low_prio_io(bool b) { m_low_prio_io = b; } @@ -73,13 +75,15 @@ namespace libtorrent struct lru_file_entry { lru_file_entry(): last_use(time_now()) {} - mutable boost::shared_ptr file_ptr; + mutable boost::intrusive_ptr file_ptr; void* key; ptime last_use; int mode; }; - typedef std::map file_set; + // maps storage pointer, file index pairs to the + // lru entry for the file + typedef std::map, lru_file_entry> file_set; file_set m_files; mutex m_mutex; diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index 12860b5ba..291c644db 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -45,9 +45,11 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + struct file; + struct TORRENT_EXPORT file_entry { - file_entry(): offset(0), size(0), file_base(0) + file_entry(): offset(0), size(0), file_base(0), file_index(0) , mtime(0), pad_file(false), hidden_attribute(false) , executable_attribute(false) , symlink_attribute(false) @@ -56,12 +58,16 @@ namespace libtorrent std::string path; std::string symlink_path; copy_ptr filehash; - size_type offset; // the offset of this file inside the torrent - size_type size; // the size of this file + // the offset of this file inside the torrent + size_type offset; + // the size of this file + size_type size; // the offset in the file where the storage starts. // This is always 0 unless parts of the torrent is // compressed into a single file, such as a so-called part file. size_type file_base; + // the index of this file, as ordered in the torrent + int file_index; time_t mtime; bool pad_file:1; bool hidden_attribute:1; diff --git a/src/file_pool.cpp b/src/file_pool.cpp index b269c624f..e82a4baf0 100644 --- a/src/file_pool.cpp +++ b/src/file_pool.cpp @@ -36,18 +36,19 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/assert.hpp" #include "libtorrent/file_pool.hpp" #include "libtorrent/error_code.hpp" +#include "libtorrent/file_storage.hpp" // for file_entry namespace libtorrent { - boost::shared_ptr file_pool::open_file(void* st, std::string const& p - , int m, error_code& ec) + boost::intrusive_ptr file_pool::open_file(void* st, std::string const& p + , file_entry const& fe, int m, error_code& ec) { TORRENT_ASSERT(st != 0); TORRENT_ASSERT(is_complete(p)); TORRENT_ASSERT((m & file::rw_mask) == file::read_only || (m & file::rw_mask) == file::read_write); mutex::scoped_lock l(m_mutex); - file_set::iterator i = m_files.find(p); + file_set::iterator i = m_files.find(std::make_pair(st, fe.file_index)); if (i != m_files.end()) { lru_file_entry& e = i->second; @@ -61,7 +62,7 @@ namespace libtorrent #if BOOST_VERSION >= 103500 ec = errors::file_collision; #endif - return boost::shared_ptr(); + return boost::intrusive_ptr(); } e.key = st; @@ -74,12 +75,13 @@ namespace libtorrent { // close the file before we open it with // the new read/write privilages - TORRENT_ASSERT(e.file_ptr.unique()); + TORRENT_ASSERT(e.file_ptr->refcount() == 1); e.file_ptr->close(); - if (!e.file_ptr->open(p, m, ec)) + std::string full_path = combine_path(p, fe.path); + if (!e.file_ptr->open(full_path, m, ec)) { m_files.erase(i); - return boost::shared_ptr(); + return boost::intrusive_ptr(); } #ifdef TORRENT_WINDOWS // file prio is supported on vista and up @@ -113,11 +115,12 @@ namespace libtorrent ec = error_code(ENOMEM, get_posix_category()); return e.file_ptr; } - if (!e.file_ptr->open(p, m, ec)) - return boost::shared_ptr(); + std::string full_path = combine_path(p, fe.path); + if (!e.file_ptr->open(full_path, m, ec)) + return boost::intrusive_ptr(); e.mode = m; e.key = st; - m_files.insert(std::make_pair(p, e)); + m_files.insert(std::make_pair(std::make_pair(st, fe.file_index), e)); TORRENT_ASSERT(e.file_ptr->is_open()); return e.file_ptr; } @@ -131,11 +134,10 @@ namespace libtorrent m_files.erase(i); } - void file_pool::release(std::string const& p) + void file_pool::release(void* st, file_entry const& fe) { mutex::scoped_lock l(m_mutex); - - file_set::iterator i = m_files.find(p); + file_set::iterator i = m_files.find(std::make_pair(st, fe.file_index)); if (i != m_files.end()) m_files.erase(i); } @@ -174,3 +176,4 @@ namespace libtorrent } } + diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 78e3f22b7..477fcec47 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -196,6 +196,7 @@ namespace libtorrent TORRENT_ASSERT(m_name == split_path(file).c_str()); m_files.push_back(file_entry()); file_entry& e = m_files.back(); + e.file_index = m_files.size() - 1; e.size = size; e.path = file; e.offset = m_total_size; @@ -227,6 +228,7 @@ namespace libtorrent m_files.push_back(ent); file_entry& e = m_files.back(); e.offset = m_total_size; + e.file_index = m_files.size() - 1; m_total_size += ent.size; } diff --git a/src/storage.cpp b/src/storage.cpp index a9941cbd7..a9bda9308 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -384,7 +384,7 @@ namespace libtorrent { size_type (file::*regular_op)(size_type file_offset , file::iovec_t const* bufs, int num_bufs, error_code& ec); - size_type (storage::*unaligned_op)(boost::shared_ptr const& f + size_type (storage::*unaligned_op)(boost::intrusive_ptr const& f , size_type file_offset, file::iovec_t const* bufs, int num_bufs , error_code& ec); int cache_setting; @@ -398,9 +398,9 @@ namespace libtorrent ~storage() { m_pool.release(this); } - size_type read_unaligned(boost::shared_ptr const& file_handle + size_type read_unaligned(boost::intrusive_ptr const& file_handle , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec); - size_type write_unaligned(boost::shared_ptr const& file_handle + size_type write_unaligned(boost::intrusive_ptr const& file_handle , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec); file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; } @@ -409,7 +409,7 @@ namespace libtorrent file_storage const& m_files; // helper function to open a file in the file pool with the right mode - boost::shared_ptr open_file(file_entry const& fe, int mode, error_code& ec) const; + boost::intrusive_ptr open_file(file_entry const& fe, int mode, error_code& ec) const; std::vector m_file_priority; std::string m_save_path; @@ -553,7 +553,7 @@ namespace libtorrent if (ec || s.file_size > file_iter->size || file_iter->size == 0) { ec.clear(); - boost::shared_ptr f = open_file(*file_iter, file::read_write, ec); + boost::intrusive_ptr f = open_file(*file_iter, file::read_write, ec); if (ec) set_error(file_path, ec); else if (f) { @@ -577,7 +577,7 @@ namespace libtorrent if (index < 0 || index >= m_files.num_files()) return; error_code ec; - boost::shared_ptr f = open_file(files().at(index), file::read_write, ec); + boost::intrusive_ptr f = open_file(files().at(index), file::read_write, ec); if (ec || !f) return; f->finalize(); @@ -604,7 +604,7 @@ namespace libtorrent { if (index < 0 || index >= m_files.num_files()) return true; std::string old_name = combine_path(m_save_path, files().at(index).path); - m_pool.release(old_name); + m_pool.release(this, files().at(index)); error_code ec; rename(old_name, combine_path(m_save_path, new_filename), ec); @@ -714,7 +714,7 @@ namespace libtorrent } error_code ec; - boost::shared_ptr file_handle = open_file(*file_iter, file::read_only, ec); + boost::intrusive_ptr file_handle = open_file(*file_iter, file::read_only, ec); if (!file_handle || ec) return slot; size_type data_start = file_handle->sparse_end(file_offset); @@ -1055,7 +1055,7 @@ ret: // open the file read only to avoid re-opening // it in case it's already opened in read-only mode error_code ec; - boost::shared_ptr f = open_file(*file_iter, file::read_only, ec); + boost::intrusive_ptr f = open_file(*file_iter, file::read_only, ec); size_type ret = 0; if (f && !ec) ret = f->phys_offset(file_offset); @@ -1143,7 +1143,7 @@ ret: int buf_pos = 0; error_code ec; - boost::shared_ptr file_handle; + boost::intrusive_ptr file_handle; int bytes_left = size; int slot_size = static_cast(m_files.piece_size(slot)); @@ -1250,7 +1250,7 @@ ret: // they read an unaligned buffer from a file that requires aligned access - size_type storage::read_unaligned(boost::shared_ptr const& file_handle + size_type storage::read_unaligned(boost::intrusive_ptr const& file_handle , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec) { const int pos_align = file_handle->pos_alignment()-1; @@ -1279,7 +1279,7 @@ ret: return size; } - size_type storage::write_unaligned(boost::shared_ptr const& file_handle + size_type storage::write_unaligned(boost::intrusive_ptr const& file_handle , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec) { TORRENT_ASSERT(false); // not implemented @@ -1306,7 +1306,7 @@ ret: return readv(&b, slot, offset, 1); } - boost::shared_ptr storage::open_file(file_entry const& fe, int mode, error_code& ec) const + boost::intrusive_ptr storage::open_file(file_entry const& fe, int mode, error_code& ec) const { int cache_setting = m_settings ? settings().disk_io_write_mode : 0; if (cache_setting == session_settings::disable_os_cache @@ -1316,7 +1316,7 @@ ret: if (!m_allocate_files) mode |= file::sparse; if (m_settings && settings().no_atime_storage) mode |= file::no_atime; - return m_pool.open_file(const_cast(this), combine_path(m_save_path, fe.path), mode, ec); + return m_pool.open_file(const_cast(this), m_save_path, fe, mode, ec); } storage_interface* default_storage_constructor(file_storage const& fs