make it possible to derive from default_storage class

This commit is contained in:
Arvid Norberg
2011-04-16 22:58:11 +00:00
parent e2d3e7c300
commit caed433cc7
2 changed files with 184 additions and 177 deletions

View File

@@ -184,6 +184,107 @@ namespace libtorrent
session_settings* m_settings; session_settings* m_settings;
}; };
class default_storage : public storage_interface, boost::noncopyable
{
public:
default_storage(file_storage const& fs, file_storage const* mapped, std::string const& path
, file_pool& fp, std::vector<boost::uint8_t> const& file_prio);
~default_storage();
void finalize_file(int file);
bool has_any_file();
bool rename_file(int index, std::string const& new_filename);
bool release_files();
bool delete_files();
bool initialize(bool allocate_files);
bool move_storage(std::string const& save_path);
int read(char* buf, int slot, int offset, int size);
int write(char const* buf, int slot, int offset, int size);
int sparse_end(int start) const;
int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs);
int writev(file::iovec_t const* buf, int slot, int offset, int num_bufs);
size_type physical_offset(int slot, int offset);
bool move_slot(int src_slot, int dst_slot);
bool swap_slots(int slot1, int slot2);
bool swap_slots3(int slot1, int slot2, int slot3);
bool verify_resume_data(lazy_entry const& rd, error_code& error);
bool write_resume_data(entry& rd) const;
// this identifies a read or write operation
// so that default_storage::readwritev() knows what to
// do when it's actually touching the file
struct fileop
{
size_type (file::*regular_op)(size_type file_offset
, file::iovec_t const* bufs, int num_bufs, error_code& ec);
size_type (default_storage::*unaligned_op)(boost::intrusive_ptr<file> const& f
, size_type file_offset, file::iovec_t const* bufs, int num_bufs
, error_code& ec);
int cache_setting;
int mode;
};
void delete_one_file(std::string const& p);
int readwritev(file::iovec_t const* bufs, int slot, int offset
, int num_bufs, fileop const&);
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 write_unaligned(boost::intrusive_ptr<file> 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; }
boost::scoped_ptr<file_storage> m_mapped_files;
file_storage const& m_files;
// helper function to open a file in the file pool with the right mode
boost::intrusive_ptr<file> open_file(file_storage::iterator fe, int mode
, error_code& ec) const;
std::vector<boost::uint8_t> m_file_priority;
std::string m_save_path;
// the file pool is typically stored in
// the session, to make all storage
// instances use the same pool
file_pool& m_pool;
int m_page_size;
bool m_allocate_files;
};
// this storage implementation does not write anything to disk
// and it pretends to read, and just leaves garbage in the buffers
// this is useful when simulating many clients on the same machine
// or when running stress tests and want to take the cost of the
// disk I/O out of the picture. This cannot be used for any kind
// of normal bittorrent operation, since it will just send garbage
// to peers and throw away all the data it downloads. It would end
// up being banned immediately
class disabled_storage : public storage_interface, boost::noncopyable
{
public:
disabled_storage(int piece_size) : m_piece_size(piece_size) {}
bool has_any_file() { return false; }
bool rename_file(int index, std::string const& new_filename) { return false; }
bool release_files() { return false; }
bool delete_files() { return false; }
bool initialize(bool allocate_files) { return false; }
bool move_storage(std::string const& save_path) { return true; }
int read(char* buf, int slot, int offset, int size) { return size; }
int write(char const* buf, int slot, int offset, int size) { return size; }
size_type physical_offset(int slot, int offset) { return 0; }
int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs);
int writev(file::iovec_t const* bufs, int slot, int offset, int num_bufs);
bool move_slot(int src_slot, int dst_slot) { return false; }
bool swap_slots(int slot1, int slot2) { return false; }
bool swap_slots3(int slot1, int slot2, int slot3) { return false; }
bool verify_resume_data(lazy_entry const& rd, error_code& error) { return false; }
bool write_resume_data(entry& rd) const { return false; }
int m_piece_size;
};
struct disk_io_thread; struct disk_io_thread;
class TORRENT_EXPORT piece_manager class TORRENT_EXPORT piece_manager

View File

@@ -341,88 +341,6 @@ namespace libtorrent
} }
#endif #endif
class storage : public storage_interface, boost::noncopyable
{
public:
storage(file_storage const& fs, file_storage const* mapped, std::string const& path
, file_pool& fp, std::vector<boost::uint8_t> const& file_prio)
: m_files(fs)
, m_file_priority(file_prio)
, m_pool(fp)
, m_page_size(page_size())
, m_allocate_files(false)
{
if (mapped) m_mapped_files.reset(new file_storage(*mapped));
TORRENT_ASSERT(m_files.begin() != m_files.end());
m_save_path = complete(path);
}
void finalize_file(int file);
bool has_any_file();
bool rename_file(int index, std::string const& new_filename);
bool release_files();
bool delete_files();
bool initialize(bool allocate_files);
bool move_storage(std::string const& save_path);
int read(char* buf, int slot, int offset, int size);
int write(char const* buf, int slot, int offset, int size);
int sparse_end(int start) const;
int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs);
int writev(file::iovec_t const* buf, int slot, int offset, int num_bufs);
size_type physical_offset(int slot, int offset);
bool move_slot(int src_slot, int dst_slot);
bool swap_slots(int slot1, int slot2);
bool swap_slots3(int slot1, int slot2, int slot3);
bool verify_resume_data(lazy_entry const& rd, error_code& error);
bool write_resume_data(entry& rd) const;
// this identifies a read or write operation
// so that storage::readwritev() knows what to
// do when it's actually touching the file
struct fileop
{
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::intrusive_ptr<file> const& f
, size_type file_offset, file::iovec_t const* bufs, int num_bufs
, error_code& ec);
int cache_setting;
int mode;
};
void delete_one_file(std::string const& p);
int readwritev(file::iovec_t const* bufs, int slot, int offset
, int num_bufs, fileop const&);
~storage()
{ m_pool.release(this); }
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 write_unaligned(boost::intrusive_ptr<file> 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; }
boost::scoped_ptr<file_storage> m_mapped_files;
file_storage const& m_files;
// helper function to open a file in the file pool with the right mode
boost::intrusive_ptr<file> open_file(file_storage::iterator fe, int mode
, error_code& ec) const;
std::vector<boost::uint8_t> m_file_priority;
std::string m_save_path;
// the file pool is typically stored in
// the session, to make all storage
// instances use the same pool
file_pool& m_pool;
int m_page_size;
bool m_allocate_files;
};
int piece_manager::hash_for_slot(int slot, partial_hash& ph, int piece_size int piece_manager::hash_for_slot(int slot, partial_hash& ph, int piece_size
, int small_piece_size, sha1_hash* small_hash) , int small_piece_size, sha1_hash* small_hash)
{ {
@@ -510,7 +428,23 @@ namespace libtorrent
return num_read; return num_read;
} }
bool storage::initialize(bool allocate_files) default_storage::default_storage(file_storage const& fs, file_storage const* mapped, std::string const& path
, file_pool& fp, std::vector<boost::uint8_t> const& file_prio)
: m_files(fs)
, m_file_priority(file_prio)
, m_pool(fp)
, m_page_size(page_size())
, m_allocate_files(false)
{
if (mapped) m_mapped_files.reset(new file_storage(*mapped));
TORRENT_ASSERT(m_files.begin() != m_files.end());
m_save_path = complete(path);
}
default_storage::~default_storage() { m_pool.release(this); }
bool default_storage::initialize(bool allocate_files)
{ {
m_allocate_files = allocate_files; m_allocate_files = allocate_files;
error_code ec; error_code ec;
@@ -574,7 +508,7 @@ namespace libtorrent
return false; return false;
} }
void storage::finalize_file(int index) void default_storage::finalize_file(int index)
{ {
TORRENT_ASSERT(index >= 0 && index < files().num_files()); TORRENT_ASSERT(index >= 0 && index < files().num_files());
if (index < 0 || index >= files().num_files()) return; if (index < 0 || index >= files().num_files()) return;
@@ -586,7 +520,7 @@ namespace libtorrent
f->finalize(); f->finalize();
} }
bool storage::has_any_file() bool default_storage::has_any_file()
{ {
file_storage::iterator i = files().begin(); file_storage::iterator i = files().begin();
file_storage::iterator end = files().end(); file_storage::iterator end = files().end();
@@ -603,7 +537,7 @@ namespace libtorrent
return false; return false;
} }
bool storage::rename_file(int index, std::string const& new_filename) bool default_storage::rename_file(int index, std::string const& new_filename)
{ {
if (index < 0 || index >= files().num_files()) return true; if (index < 0 || index >= files().num_files()) return true;
std::string old_name = combine_path(m_save_path, files().file_path(files().at(index))); std::string old_name = combine_path(m_save_path, files().file_path(files().at(index)));
@@ -627,13 +561,13 @@ namespace libtorrent
return false; return false;
} }
bool storage::release_files() bool default_storage::release_files()
{ {
m_pool.release(this); m_pool.release(this);
return false; return false;
} }
void storage::delete_one_file(std::string const& p) void default_storage::delete_one_file(std::string const& p)
{ {
error_code ec; error_code ec;
remove(p, ec); remove(p, ec);
@@ -642,7 +576,7 @@ namespace libtorrent
set_error(p, ec); set_error(p, ec);
} }
bool storage::delete_files() bool default_storage::delete_files()
{ {
// make sure we don't have the files open // make sure we don't have the files open
m_pool.release(this); m_pool.release(this);
@@ -679,7 +613,7 @@ namespace libtorrent
return false; return false;
} }
bool storage::write_resume_data(entry& rd) const bool default_storage::write_resume_data(entry& rd) const
{ {
TORRENT_ASSERT(rd.type() == entry::dictionary_t); TORRENT_ASSERT(rd.type() == entry::dictionary_t);
@@ -699,7 +633,7 @@ namespace libtorrent
return false; return false;
} }
int storage::sparse_end(int slot) const int default_storage::sparse_end(int slot) const
{ {
TORRENT_ASSERT(slot >= 0); TORRENT_ASSERT(slot >= 0);
TORRENT_ASSERT(slot < m_files.num_pieces()); TORRENT_ASSERT(slot < m_files.num_pieces());
@@ -725,7 +659,7 @@ namespace libtorrent
return int((data_start + m_files.piece_length() - 1) / m_files.piece_length()); return int((data_start + m_files.piece_length() - 1) / m_files.piece_length());
} }
bool storage::verify_resume_data(lazy_entry const& rd, error_code& error) bool default_storage::verify_resume_data(lazy_entry const& rd, error_code& error)
{ {
// TODO: make this more generic to not just work if files have been // TODO: make this more generic to not just work if files have been
// renamed, but also if they have been merged into a single file for instance // renamed, but also if they have been merged into a single file for instance
@@ -847,7 +781,7 @@ namespace libtorrent
} }
// returns true on success // returns true on success
bool storage::move_storage(std::string const& sp) bool default_storage::move_storage(std::string const& sp)
{ {
std::string save_path = complete(sp); std::string save_path = complete(sp);
@@ -903,7 +837,7 @@ namespace libtorrent
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
/* /*
void storage::shuffle() void default_storage::shuffle()
{ {
int num_pieces = files().num_pieces(); int num_pieces = files().num_pieces();
@@ -950,7 +884,7 @@ namespace libtorrent
bufs[num_bufs].iov_len = (std::min)(disk_pool()->block_size(), size) bufs[num_bufs].iov_len = (std::min)(disk_pool()->block_size(), size)
bool storage::move_slot(int src_slot, int dst_slot) bool default_storage::move_slot(int src_slot, int dst_slot)
{ {
bool r = true; bool r = true;
int piece_size = m_files.piece_size(dst_slot); int piece_size = m_files.piece_size(dst_slot);
@@ -966,7 +900,7 @@ ret:
return r; return r;
} }
bool storage::swap_slots(int slot1, int slot2) bool default_storage::swap_slots(int slot1, int slot2)
{ {
bool r = true; bool r = true;
@@ -989,7 +923,7 @@ ret:
return r; return r;
} }
bool storage::swap_slots3(int slot1, int slot2, int slot3) bool default_storage::swap_slots3(int slot1, int slot2, int slot3)
{ {
bool r = true; bool r = true;
@@ -1019,7 +953,7 @@ ret:
return r; return r;
} }
int storage::writev(file::iovec_t const* bufs, int slot, int offset int default_storage::writev(file::iovec_t const* bufs, int slot, int offset
, int num_bufs) , int num_bufs)
{ {
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
@@ -1030,7 +964,7 @@ ret:
<< physical_offset(slot, offset) << std::endl; << physical_offset(slot, offset) << std::endl;
} }
#endif #endif
fileop op = { &file::writev, &storage::write_unaligned fileop op = { &file::writev, &default_storage::write_unaligned
, m_settings ? settings().disk_io_write_mode : 0, file::read_write }; , m_settings ? settings().disk_io_write_mode : 0, file::read_write };
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
int ret = readwritev(bufs, slot, offset, num_bufs, op); int ret = readwritev(bufs, slot, offset, num_bufs, op);
@@ -1045,7 +979,7 @@ ret:
#endif #endif
} }
size_type storage::physical_offset(int slot, int offset) size_type default_storage::physical_offset(int slot, int offset)
{ {
TORRENT_ASSERT(slot >= 0); TORRENT_ASSERT(slot >= 0);
TORRENT_ASSERT(slot < m_files.num_pieces()); TORRENT_ASSERT(slot < m_files.num_pieces());
@@ -1077,7 +1011,7 @@ ret:
return ret; return ret;
} }
int storage::readv(file::iovec_t const* bufs, int slot, int offset int default_storage::readv(file::iovec_t const* bufs, int slot, int offset
, int num_bufs) , int num_bufs)
{ {
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
@@ -1088,7 +1022,7 @@ ret:
<< physical_offset(slot, offset) << std::endl; << physical_offset(slot, offset) << std::endl;
} }
#endif #endif
fileop op = { &file::readv, &storage::read_unaligned fileop op = { &file::readv, &default_storage::read_unaligned
, m_settings ? settings().disk_io_read_mode : 0, file::read_only }; , m_settings ? settings().disk_io_read_mode : 0, file::read_only };
#ifdef TORRENT_SIMULATE_SLOW_READ #ifdef TORRENT_SIMULATE_SLOW_READ
boost::thread::sleep(boost::get_system_time() boost::thread::sleep(boost::get_system_time()
@@ -1112,7 +1046,7 @@ ret:
// of that is the same for reading and writing. This function // of that is the same for reading and writing. This function
// is a template, and the fileop decides what to do with the // is a template, and the fileop decides what to do with the
// file and the buffers. // file and the buffers.
int storage::readwritev(file::iovec_t const* bufs, int slot, int offset int default_storage::readwritev(file::iovec_t const* bufs, int slot, int offset
, int num_bufs, fileop const& op) , int num_bufs, fileop const& op)
{ {
TORRENT_ASSERT(bufs != 0); TORRENT_ASSERT(bufs != 0);
@@ -1272,7 +1206,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::intrusive_ptr<file> const& file_handle size_type default_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;
@@ -1309,7 +1243,7 @@ ret:
// this is the really expensive one. To write unaligned, we need to read // this is the really expensive one. To write unaligned, we need to read
// an aligned block, overlay the unaligned buffer, and then write it back // an aligned block, overlay the unaligned buffer, and then write it back
size_type storage::write_unaligned(boost::intrusive_ptr<file> const& file_handle size_type default_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)
{ {
const int pos_align = file_handle->pos_alignment()-1; const int pos_align = file_handle->pos_alignment()-1;
@@ -1355,7 +1289,7 @@ ret:
return size; return size;
} }
int storage::write( int default_storage::write(
const char* buf const char* buf
, int slot , int slot
, int offset , int offset
@@ -1365,7 +1299,7 @@ ret:
return writev(&b, slot, offset, 1); return writev(&b, slot, offset, 1);
} }
int storage::read( int default_storage::read(
char* buf char* buf
, int slot , int slot
, int offset , int offset
@@ -1375,7 +1309,7 @@ ret:
return readv(&b, slot, offset, 1); return readv(&b, slot, offset, 1);
} }
boost::intrusive_ptr<file> storage::open_file(file_storage::iterator fe, int mode boost::intrusive_ptr<file> default_storage::open_file(file_storage::iterator fe, int mode
, error_code& ec) const , 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;
@@ -1386,38 +1320,17 @@ 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), m_save_path, fe, files(), mode, ec); return m_pool.open_file(const_cast<default_storage*>(this), m_save_path, fe, files(), mode, ec);
} }
storage_interface* default_storage_constructor(file_storage const& fs storage_interface* default_storage_constructor(file_storage const& fs
, file_storage const* mapped, std::string const& path, file_pool& fp , file_storage const* mapped, std::string const& path, file_pool& fp
, std::vector<boost::uint8_t> const& file_prio) , std::vector<boost::uint8_t> const& file_prio)
{ {
return new storage(fs, mapped, path, fp, file_prio); return new default_storage(fs, mapped, path, fp, file_prio);
} }
// this storage implementation does not write anything to disk int disabled_storage::readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs)
// and it pretends to read, and just leaves garbage in the buffers
// this is useful when simulating many clients on the same machine
// or when running stress tests and want to take the cost of the
// disk I/O out of the picture. This cannot be used for any kind
// of normal bittorrent operation, since it will just send garbage
// to peers and throw away all the data it downloads. It would end
// up being banned immediately
class disabled_storage : public storage_interface, boost::noncopyable
{
public:
disabled_storage(int piece_size) : m_piece_size(piece_size) {}
bool has_any_file() { return false; }
bool rename_file(int index, std::string const& new_filename) { return false; }
bool release_files() { return false; }
bool delete_files() { return false; }
bool initialize(bool allocate_files) { return false; }
bool move_storage(std::string const& save_path) { return true; }
int read(char* buf, int slot, int offset, int size) { return size; }
int write(char const* buf, int slot, int offset, int size) { return size; }
size_type physical_offset(int slot, int offset) { return 0; }
int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs)
{ {
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
disk_buffer_pool* pool = disk_pool(); disk_buffer_pool* pool = disk_pool();
@@ -1439,7 +1352,8 @@ ret:
#endif #endif
return ret; return ret;
} }
int writev(file::iovec_t const* bufs, int slot, int offset, int num_bufs)
int disabled_storage::writev(file::iovec_t const* bufs, int slot, int offset, int num_bufs)
{ {
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
disk_buffer_pool* pool = disk_pool(); disk_buffer_pool* pool = disk_pool();
@@ -1461,14 +1375,6 @@ ret:
#endif #endif
return ret; return ret;
} }
bool move_slot(int src_slot, int dst_slot) { return false; }
bool swap_slots(int slot1, int slot2) { return false; }
bool swap_slots3(int slot1, int slot2, int slot3) { return false; }
bool verify_resume_data(lazy_entry const& rd, error_code& error) { return false; }
bool write_resume_data(entry& rd) const { return false; }
int m_piece_size;
};
storage_interface* disabled_storage_constructor(file_storage const& fs storage_interface* disabled_storage_constructor(file_storage const& fs
, file_storage const* mapped, std::string const& path, file_pool& fp , file_storage const* mapped, std::string const& path, file_pool& fp