optimized file_pool lookups and string handling

This commit is contained in:
Arvid Norberg 2010-08-23 08:48:02 +00:00
parent b747cdab8a
commit b7b542f587
8 changed files with 73 additions and 42 deletions

View File

@ -60,6 +60,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/file.hpp" #include "libtorrent/file.hpp"
#include "libtorrent/peer_info.hpp" #include "libtorrent/peer_info.hpp"
#include "libtorrent/socket_io.hpp" // print_address #include "libtorrent/socket_io.hpp" // print_address
#include "libtorrent/time.hpp"
using boost::bind; using boost::bind;
@ -130,16 +131,29 @@ bool sleep_and_input(char* c, int sleep)
// sets the terminal to single-character mode // sets the terminal to single-character mode
// and resets when destructed // and resets when destructed
set_keypress s; set_keypress s;
libtorrent::ptime start = libtorrent::time_now_hires();
int ret = 0;
retry:
fd_set set; fd_set set;
FD_ZERO(&set); FD_ZERO(&set);
FD_SET(0, &set); FD_SET(0, &set);
timeval tv = {sleep, 0}; 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); *c = getc(stdin);
return true; 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); libtorrent::sleep(500);
return false; return false;
} }

View File

@ -52,7 +52,9 @@ struct peer_conn
: s(ios) : s(ios)
, read_pos(0) , read_pos(0)
, state(handshaking) , state(handshaking)
, pieces(num_pieces) // don't request anything from the last piece
// to keep things simple
, pieces(num_pieces - 1)
, block(0) , block(0)
, blocks_per_piece(blocks_pp) , blocks_per_piece(blocks_pp)
, info_hash(ih) , 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 conns.push_back(new peer_conn(ios, ti.num_pieces(), ti.piece_length() / 16 / 1024
, ep, (char const*)&ti.info_hash()[0])); , ep, (char const*)&ti.info_hash()[0]));
libtorrent::sleep(1); libtorrent::sleep(1);
ios.poll_one();
} }
ios.run(); ios.run();

View File

@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
#ifdef TORRENT_WINDOWS #ifdef TORRENT_WINDOWS
// windows part // windows part
@ -164,10 +165,8 @@ namespace libtorrent
bool m_done; bool m_done;
}; };
class TORRENT_EXPORT file: public boost::noncopyable struct TORRENT_EXPORT file: boost::noncopyable, intrusive_ptr_base<file>
{ {
public:
enum enum
{ {
// when a file is opened with no_buffer // when a file is opened with no_buffer

View File

@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma warning(push, 1) #pragma warning(push, 1)
#endif #endif
#include <boost/shared_ptr.hpp> #include <boost/intrusive_ptr.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -50,14 +50,16 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
struct file_entry;
struct TORRENT_EXPORT file_pool : boost::noncopyable struct TORRENT_EXPORT file_pool : boost::noncopyable
{ {
file_pool(int size = 40): m_size(size), m_low_prio_io(true) {} file_pool(int size = 40): m_size(size), m_low_prio_io(true) {}
boost::shared_ptr<file> open_file(void* st, std::string const& p boost::intrusive_ptr<file> open_file(void* st, std::string const& p
, int m, error_code& ec); , file_entry const& fe, int m, error_code& ec);
void release(void* st); void release(void* st);
void release(std::string const& p); void release(void* st, file_entry const& fe);
void resize(int size); void resize(int size);
int size_limit() const { return m_size; } int size_limit() const { return m_size; }
void set_low_prio_io(bool b) { m_low_prio_io = b; } void set_low_prio_io(bool b) { m_low_prio_io = b; }
@ -73,13 +75,15 @@ namespace libtorrent
struct lru_file_entry struct lru_file_entry
{ {
lru_file_entry(): last_use(time_now()) {} lru_file_entry(): last_use(time_now()) {}
mutable boost::shared_ptr<file> file_ptr; mutable boost::intrusive_ptr<file> file_ptr;
void* key; void* key;
ptime last_use; ptime last_use;
int mode; int mode;
}; };
typedef std::map<std::string, lru_file_entry> file_set; // maps storage pointer, file index pairs to the
// lru entry for the file
typedef std::map<std::pair<void*, int>, lru_file_entry> file_set;
file_set m_files; file_set m_files;
mutex m_mutex; mutex m_mutex;

View File

@ -45,9 +45,11 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
struct file;
struct TORRENT_EXPORT file_entry 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) , mtime(0), pad_file(false), hidden_attribute(false)
, executable_attribute(false) , executable_attribute(false)
, symlink_attribute(false) , symlink_attribute(false)
@ -56,12 +58,16 @@ namespace libtorrent
std::string path; std::string path;
std::string symlink_path; std::string symlink_path;
copy_ptr<sha1_hash> filehash; copy_ptr<sha1_hash> filehash;
size_type offset; // the offset of this file inside the torrent // the offset of this file inside the torrent
size_type size; // the size of this file size_type offset;
// the size of this file
size_type size;
// the offset in the file where the storage starts. // the offset in the file where the storage starts.
// This is always 0 unless parts of the torrent is // This is always 0 unless parts of the torrent is
// compressed into a single file, such as a so-called part file. // compressed into a single file, such as a so-called part file.
size_type file_base; size_type file_base;
// the index of this file, as ordered in the torrent
int file_index;
time_t mtime; time_t mtime;
bool pad_file:1; bool pad_file:1;
bool hidden_attribute:1; bool hidden_attribute:1;

View File

@ -36,18 +36,19 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp" #include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
#include "libtorrent/file_storage.hpp" // for file_entry
namespace libtorrent namespace libtorrent
{ {
boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
, int m, error_code& ec) , file_entry const& fe, int m, error_code& ec)
{ {
TORRENT_ASSERT(st != 0); TORRENT_ASSERT(st != 0);
TORRENT_ASSERT(is_complete(p)); TORRENT_ASSERT(is_complete(p));
TORRENT_ASSERT((m & file::rw_mask) == file::read_only TORRENT_ASSERT((m & file::rw_mask) == file::read_only
|| (m & file::rw_mask) == file::read_write); || (m & file::rw_mask) == file::read_write);
mutex::scoped_lock l(m_mutex); 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()) if (i != m_files.end())
{ {
lru_file_entry& e = i->second; lru_file_entry& e = i->second;
@ -61,7 +62,7 @@ namespace libtorrent
#if BOOST_VERSION >= 103500 #if BOOST_VERSION >= 103500
ec = errors::file_collision; ec = errors::file_collision;
#endif #endif
return boost::shared_ptr<file>(); return boost::intrusive_ptr<file>();
} }
e.key = st; e.key = st;
@ -74,12 +75,13 @@ namespace libtorrent
{ {
// close the file before we open it with // close the file before we open it with
// the new read/write privilages // the new read/write privilages
TORRENT_ASSERT(e.file_ptr.unique()); TORRENT_ASSERT(e.file_ptr->refcount() == 1);
e.file_ptr->close(); 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); m_files.erase(i);
return boost::shared_ptr<file>(); return boost::intrusive_ptr<file>();
} }
#ifdef TORRENT_WINDOWS #ifdef TORRENT_WINDOWS
// file prio is supported on vista and up // file prio is supported on vista and up
@ -113,11 +115,12 @@ namespace libtorrent
ec = error_code(ENOMEM, get_posix_category()); ec = error_code(ENOMEM, get_posix_category());
return e.file_ptr; return e.file_ptr;
} }
if (!e.file_ptr->open(p, m, ec)) std::string full_path = combine_path(p, fe.path);
return boost::shared_ptr<file>(); if (!e.file_ptr->open(full_path, m, ec))
return boost::intrusive_ptr<file>();
e.mode = m; e.mode = m;
e.key = st; 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()); TORRENT_ASSERT(e.file_ptr->is_open());
return e.file_ptr; return e.file_ptr;
} }
@ -131,11 +134,10 @@ namespace libtorrent
m_files.erase(i); 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); mutex::scoped_lock l(m_mutex);
file_set::iterator i = m_files.find(std::make_pair(st, fe.file_index));
file_set::iterator i = m_files.find(p);
if (i != m_files.end()) m_files.erase(i); if (i != m_files.end()) m_files.erase(i);
} }
@ -174,3 +176,4 @@ namespace libtorrent
} }
} }

View File

@ -196,6 +196,7 @@ namespace libtorrent
TORRENT_ASSERT(m_name == split_path(file).c_str()); TORRENT_ASSERT(m_name == split_path(file).c_str());
m_files.push_back(file_entry()); m_files.push_back(file_entry());
file_entry& e = m_files.back(); file_entry& e = m_files.back();
e.file_index = m_files.size() - 1;
e.size = size; e.size = size;
e.path = file; e.path = file;
e.offset = m_total_size; e.offset = m_total_size;
@ -227,6 +228,7 @@ namespace libtorrent
m_files.push_back(ent); m_files.push_back(ent);
file_entry& e = m_files.back(); file_entry& e = m_files.back();
e.offset = m_total_size; e.offset = m_total_size;
e.file_index = m_files.size() - 1;
m_total_size += ent.size; m_total_size += ent.size;
} }

View File

@ -384,7 +384,7 @@ namespace libtorrent
{ {
size_type (file::*regular_op)(size_type file_offset size_type (file::*regular_op)(size_type file_offset
, file::iovec_t const* bufs, int num_bufs, error_code& ec); , file::iovec_t const* bufs, int num_bufs, error_code& ec);
size_type (storage::*unaligned_op)(boost::shared_ptr<file> const& f size_type (storage::*unaligned_op)(boost::intrusive_ptr<file> const& f
, size_type file_offset, file::iovec_t const* bufs, int num_bufs , size_type file_offset, file::iovec_t const* bufs, int num_bufs
, error_code& ec); , error_code& ec);
int cache_setting; int cache_setting;
@ -398,9 +398,9 @@ namespace libtorrent
~storage() ~storage()
{ m_pool.release(this); } { m_pool.release(this); }
size_type read_unaligned(boost::shared_ptr<file> const& file_handle size_type read_unaligned(boost::intrusive_ptr<file> const& file_handle
, size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec); , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec);
size_type write_unaligned(boost::shared_ptr<file> const& file_handle size_type write_unaligned(boost::intrusive_ptr<file> const& file_handle
, size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec); , 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; } 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; file_storage const& m_files;
// helper function to open a file in the file pool with the right mode // helper function to open a file in the file pool with the right mode
boost::shared_ptr<file> open_file(file_entry const& fe, int mode, error_code& ec) const; boost::intrusive_ptr<file> open_file(file_entry const& fe, int mode, error_code& ec) const;
std::vector<boost::uint8_t> m_file_priority; std::vector<boost::uint8_t> m_file_priority;
std::string m_save_path; std::string m_save_path;
@ -553,7 +553,7 @@ namespace libtorrent
if (ec || s.file_size > file_iter->size || file_iter->size == 0) if (ec || s.file_size > file_iter->size || file_iter->size == 0)
{ {
ec.clear(); ec.clear();
boost::shared_ptr<file> f = open_file(*file_iter, file::read_write, ec); boost::intrusive_ptr<file> f = open_file(*file_iter, file::read_write, ec);
if (ec) set_error(file_path, ec); if (ec) set_error(file_path, ec);
else if (f) else if (f)
{ {
@ -577,7 +577,7 @@ namespace libtorrent
if (index < 0 || index >= m_files.num_files()) return; if (index < 0 || index >= m_files.num_files()) return;
error_code ec; error_code ec;
boost::shared_ptr<file> f = open_file(files().at(index), file::read_write, ec); boost::intrusive_ptr<file> f = open_file(files().at(index), file::read_write, ec);
if (ec || !f) return; if (ec || !f) return;
f->finalize(); f->finalize();
@ -604,7 +604,7 @@ namespace libtorrent
{ {
if (index < 0 || index >= m_files.num_files()) return true; if (index < 0 || index >= m_files.num_files()) return true;
std::string old_name = combine_path(m_save_path, files().at(index).path); 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; error_code ec;
rename(old_name, combine_path(m_save_path, new_filename), ec); rename(old_name, combine_path(m_save_path, new_filename), ec);
@ -714,7 +714,7 @@ namespace libtorrent
} }
error_code ec; error_code ec;
boost::shared_ptr<file> file_handle = open_file(*file_iter, file::read_only, ec); boost::intrusive_ptr<file> file_handle = open_file(*file_iter, file::read_only, ec);
if (!file_handle || ec) return slot; if (!file_handle || ec) return slot;
size_type data_start = file_handle->sparse_end(file_offset); size_type data_start = file_handle->sparse_end(file_offset);
@ -1055,7 +1055,7 @@ ret:
// open the file read only to avoid re-opening // open the file read only to avoid re-opening
// it in case it's already opened in read-only mode // it in case it's already opened in read-only mode
error_code ec; error_code ec;
boost::shared_ptr<file> f = open_file(*file_iter, file::read_only, ec); boost::intrusive_ptr<file> f = open_file(*file_iter, file::read_only, ec);
size_type ret = 0; size_type ret = 0;
if (f && !ec) ret = f->phys_offset(file_offset); if (f && !ec) ret = f->phys_offset(file_offset);
@ -1143,7 +1143,7 @@ ret:
int buf_pos = 0; int buf_pos = 0;
error_code ec; error_code ec;
boost::shared_ptr<file> file_handle; boost::intrusive_ptr<file> file_handle;
int bytes_left = size; int bytes_left = size;
int slot_size = static_cast<int>(m_files.piece_size(slot)); int slot_size = static_cast<int>(m_files.piece_size(slot));
@ -1250,7 +1250,7 @@ ret:
// they read an unaligned buffer from a file that requires aligned access // they read an unaligned buffer from a file that requires aligned access
size_type storage::read_unaligned(boost::shared_ptr<file> const& file_handle size_type storage::read_unaligned(boost::intrusive_ptr<file> const& file_handle
, size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec) , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec)
{ {
const int pos_align = file_handle->pos_alignment()-1; const int pos_align = file_handle->pos_alignment()-1;
@ -1279,7 +1279,7 @@ ret:
return size; return size;
} }
size_type storage::write_unaligned(boost::shared_ptr<file> const& file_handle size_type storage::write_unaligned(boost::intrusive_ptr<file> const& file_handle
, size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec) , size_type file_offset, file::iovec_t const* bufs, int num_bufs, error_code& ec)
{ {
TORRENT_ASSERT(false); // not implemented TORRENT_ASSERT(false); // not implemented
@ -1306,7 +1306,7 @@ ret:
return readv(&b, slot, offset, 1); return readv(&b, slot, offset, 1);
} }
boost::shared_ptr<file> storage::open_file(file_entry const& fe, int mode, error_code& ec) const boost::intrusive_ptr<file> storage::open_file(file_entry const& fe, int mode, error_code& ec) const
{ {
int cache_setting = m_settings ? settings().disk_io_write_mode : 0; int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
if (cache_setting == session_settings::disable_os_cache if (cache_setting == session_settings::disable_os_cache
@ -1316,7 +1316,7 @@ ret:
if (!m_allocate_files) mode |= file::sparse; if (!m_allocate_files) mode |= file::sparse;
if (m_settings && settings().no_atime_storage) mode |= file::no_atime; if (m_settings && settings().no_atime_storage) mode |= file::no_atime;
return m_pool.open_file(const_cast<storage*>(this), combine_path(m_save_path, fe.path), mode, ec); return m_pool.open_file(const_cast<storage*>(this), m_save_path, fe, mode, ec);
} }
storage_interface* default_storage_constructor(file_storage const& fs storage_interface* default_storage_constructor(file_storage const& fs