simplify the buffer_allocator_interface
This commit is contained in:
parent
cda715c152
commit
192ef4962b
|
@ -622,10 +622,6 @@ namespace libtorrent
|
||||||
|
|
||||||
// implements buffer_allocator_interface
|
// implements buffer_allocator_interface
|
||||||
void free_disk_buffer(char* buf) override;
|
void free_disk_buffer(char* buf) override;
|
||||||
disk_buffer_holder allocate_disk_buffer(char const* category) override;
|
|
||||||
disk_buffer_holder allocate_disk_buffer(bool& exceeded
|
|
||||||
, std::shared_ptr<disk_observer> o
|
|
||||||
, char const* category) override;
|
|
||||||
void reclaim_blocks(span<block_cache_reference> refs) override;
|
void reclaim_blocks(span<block_cache_reference> refs) override;
|
||||||
void do_reclaim_blocks();
|
void do_reclaim_blocks();
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,6 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
virtual void free_disk_buffer(char* b) = 0;
|
virtual void free_disk_buffer(char* b) = 0;
|
||||||
virtual void reclaim_blocks(span<aux::block_cache_reference> refs) = 0;
|
virtual void reclaim_blocks(span<aux::block_cache_reference> refs) = 0;
|
||||||
virtual disk_buffer_holder allocate_disk_buffer(char const* category) = 0;
|
|
||||||
virtual disk_buffer_holder allocate_disk_buffer(bool& exceeded
|
|
||||||
, std::shared_ptr<disk_observer> o
|
|
||||||
, char const* category) = 0;
|
|
||||||
protected:
|
protected:
|
||||||
~buffer_allocator_interface() {}
|
~buffer_allocator_interface() {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/bdecode.hpp"
|
#include "libtorrent/bdecode.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "libtorrent/units.hpp"
|
#include "libtorrent/units.hpp"
|
||||||
#include "libtorrent/aux_/vector.hpp"
|
#include "libtorrent/aux_/vector.hpp"
|
||||||
|
@ -77,8 +78,8 @@ namespace libtorrent
|
||||||
virtual void async_read(storage_interface* storage, peer_request const& r
|
virtual void async_read(storage_interface* storage, peer_request const& r
|
||||||
, std::function<void(aux::block_cache_reference ref, char* block
|
, std::function<void(aux::block_cache_reference ref, char* block
|
||||||
, int flags, storage_error const& se)> handler, void* requester, std::uint8_t flags = 0) = 0;
|
, int flags, storage_error const& se)> handler, void* requester, std::uint8_t flags = 0) = 0;
|
||||||
virtual void async_write(storage_interface* storage, peer_request const& r
|
virtual bool async_write(storage_interface* storage, peer_request const& r
|
||||||
, disk_buffer_holder buffer
|
, char const* buf, std::shared_ptr<disk_observer> o
|
||||||
, std::function<void(storage_error const&)> handler
|
, std::function<void(storage_error const&)> handler
|
||||||
, std::uint8_t flags = 0) = 0;
|
, std::uint8_t flags = 0) = 0;
|
||||||
virtual void async_hash(storage_interface* storage, piece_index_t piece, std::uint8_t flags
|
virtual void async_hash(storage_interface* storage, piece_index_t piece, std::uint8_t flags
|
||||||
|
|
|
@ -294,8 +294,8 @@ namespace libtorrent
|
||||||
void async_read(storage_interface* storage, peer_request const& r
|
void async_read(storage_interface* storage, peer_request const& r
|
||||||
, std::function<void(aux::block_cache_reference ref, char* block
|
, std::function<void(aux::block_cache_reference ref, char* block
|
||||||
, int flags, storage_error const& se)> handler, void* requester, std::uint8_t flags = 0) override;
|
, int flags, storage_error const& se)> handler, void* requester, std::uint8_t flags = 0) override;
|
||||||
void async_write(storage_interface* storage, peer_request const& r
|
bool async_write(storage_interface* storage, peer_request const& r
|
||||||
, disk_buffer_holder buffer
|
, char const* buf, std::shared_ptr<disk_observer> o
|
||||||
, std::function<void(storage_error const&)> handler
|
, std::function<void(storage_error const&)> handler
|
||||||
, std::uint8_t flags = 0) override;
|
, std::uint8_t flags = 0) override;
|
||||||
void async_hash(storage_interface* storage, piece_index_t piece, std::uint8_t flags
|
void async_hash(storage_interface* storage, piece_index_t piece, std::uint8_t flags
|
||||||
|
@ -332,16 +332,7 @@ namespace libtorrent
|
||||||
// implements buffer_allocator_interface
|
// implements buffer_allocator_interface
|
||||||
void reclaim_blocks(span<aux::block_cache_reference> ref) override;
|
void reclaim_blocks(span<aux::block_cache_reference> ref) override;
|
||||||
void free_disk_buffer(char* buf) override { m_disk_cache.free_buffer(buf); }
|
void free_disk_buffer(char* buf) override { m_disk_cache.free_buffer(buf); }
|
||||||
disk_buffer_holder allocate_disk_buffer(char const* category) override
|
|
||||||
{
|
|
||||||
bool exceed = false;
|
|
||||||
return allocate_disk_buffer(exceed, std::shared_ptr<disk_observer>(), category);
|
|
||||||
}
|
|
||||||
|
|
||||||
void trigger_cache_trim();
|
void trigger_cache_trim();
|
||||||
disk_buffer_holder allocate_disk_buffer(bool& exceeded, std::shared_ptr<disk_observer> o
|
|
||||||
, char const* category) override;
|
|
||||||
|
|
||||||
void update_stats_counters(counters& c) const override;
|
void update_stats_counters(counters& c) const override;
|
||||||
void get_cache_info(cache_status* ret, bool no_pieces = true
|
void get_cache_info(cache_status* ret, bool no_pieces = true
|
||||||
, storage_interface const* storage = 0) const override;
|
, storage_interface const* storage = 0) const override;
|
||||||
|
|
|
@ -550,7 +550,6 @@ namespace libtorrent
|
||||||
void incoming_dont_have(piece_index_t piece_index);
|
void incoming_dont_have(piece_index_t piece_index);
|
||||||
void incoming_bitfield(typed_bitfield<piece_index_t> const& bits);
|
void incoming_bitfield(typed_bitfield<piece_index_t> const& bits);
|
||||||
void incoming_request(peer_request const& r);
|
void incoming_request(peer_request const& r);
|
||||||
void incoming_piece(peer_request const& p, disk_buffer_holder data);
|
|
||||||
void incoming_piece(peer_request const& p, char const* data);
|
void incoming_piece(peer_request const& p, char const* data);
|
||||||
void incoming_piece_fragment(int bytes);
|
void incoming_piece_fragment(int bytes);
|
||||||
void start_receive_piece(peer_request const& r);
|
void start_receive_piece(peer_request const& r);
|
||||||
|
|
|
@ -1625,14 +1625,19 @@ namespace libtorrent
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_io_thread::async_write(storage_interface* storage, peer_request const& r
|
bool disk_io_thread::async_write(storage_interface* storage, peer_request const& r
|
||||||
, disk_buffer_holder buffer
|
, char const* buf, std::shared_ptr<disk_observer> o
|
||||||
, std::function<void(storage_error const&)> handler
|
, std::function<void(storage_error const&)> handler
|
||||||
, std::uint8_t const flags)
|
, std::uint8_t const flags)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(r.length <= m_disk_cache.block_size());
|
TORRENT_ASSERT(r.length <= m_disk_cache.block_size());
|
||||||
TORRENT_ASSERT(r.length <= 16 * 1024);
|
TORRENT_ASSERT(r.length <= 16 * 1024);
|
||||||
|
|
||||||
|
bool exceeded = false;
|
||||||
|
disk_buffer_holder buffer(*this, m_disk_cache.allocate_buffer(exceeded, o, "receive buffer"));
|
||||||
|
if (!buffer) throw std::bad_alloc();
|
||||||
|
std::memcpy(buffer.get(), buf, r.length);
|
||||||
|
|
||||||
disk_io_job* j = allocate_job(disk_io_job::write);
|
disk_io_job* j = allocate_job(disk_io_job::write);
|
||||||
j->storage = storage->shared_from_this();
|
j->storage = storage->shared_from_this();
|
||||||
j->piece = r.piece;
|
j->piece = r.piece;
|
||||||
|
@ -1690,7 +1695,7 @@ namespace libtorrent
|
||||||
// make the holder give up ownership of the buffer
|
// make the holder give up ownership of the buffer
|
||||||
// since the job was successfully queued up
|
// since the job was successfully queued up
|
||||||
buffer.release();
|
buffer.release();
|
||||||
return;
|
return exceeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> l(m_cache_mutex);
|
std::unique_lock<std::mutex> l(m_cache_mutex);
|
||||||
|
@ -1720,12 +1725,13 @@ namespace libtorrent
|
||||||
|
|
||||||
// if we added the block (regardless of whether we also
|
// if we added the block (regardless of whether we also
|
||||||
// issued a flush job or not), we're done.
|
// issued a flush job or not), we're done.
|
||||||
return;
|
return exceeded;
|
||||||
}
|
}
|
||||||
l.unlock();
|
l.unlock();
|
||||||
|
|
||||||
add_job(j);
|
add_job(j);
|
||||||
buffer.release();
|
buffer.release();
|
||||||
|
return exceeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_io_thread::async_hash(storage_interface* storage
|
void disk_io_thread::async_hash(storage_interface* storage
|
||||||
|
@ -3176,14 +3182,6 @@ namespace libtorrent
|
||||||
submit_jobs();
|
submit_jobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
disk_buffer_holder disk_io_thread::allocate_disk_buffer(bool& exceeded
|
|
||||||
, std::shared_ptr<disk_observer> o
|
|
||||||
, char const* category)
|
|
||||||
{
|
|
||||||
char* ret = m_disk_cache.allocate_buffer(exceeded, o, category);
|
|
||||||
return disk_buffer_holder(*this, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disk_io_thread::add_completed_jobs(jobqueue_t& jobs)
|
void disk_io_thread::add_completed_jobs(jobqueue_t& jobs)
|
||||||
{
|
{
|
||||||
jobqueue_t new_completed_jobs;
|
jobqueue_t new_completed_jobs;
|
||||||
|
|
|
@ -2588,39 +2588,6 @@ namespace libtorrent
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
void peer_connection::incoming_piece(peer_request const& p, char const* data)
|
void peer_connection::incoming_piece(peer_request const& p, char const* data)
|
||||||
{
|
|
||||||
TORRENT_ASSERT(is_single_thread());
|
|
||||||
bool exceeded = false;
|
|
||||||
disk_buffer_holder buffer
|
|
||||||
= m_allocator.allocate_disk_buffer(exceeded, self(), "receive buffer");
|
|
||||||
|
|
||||||
if (!buffer)
|
|
||||||
{
|
|
||||||
disconnect(errors::no_memory, op_alloc_recvbuf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// every peer is entitled to have two disk blocks allocated at any given
|
|
||||||
// time, regardless of whether the cache size is exceeded or not. If this
|
|
||||||
// was not the case, when the cache size setting is very small, most peers
|
|
||||||
// would be blocked most of the time, because the disk cache would
|
|
||||||
// continuously be in exceeded state. Only rarely would it actually drop
|
|
||||||
// down to 0 and unblock all peers.
|
|
||||||
if (exceeded && m_outstanding_writing_bytes > 0)
|
|
||||||
{
|
|
||||||
if ((m_channel_state[download_channel] & peer_info::bw_disk) == 0)
|
|
||||||
m_counters.inc_stats_counter(counters::num_peers_down_disk);
|
|
||||||
m_channel_state[download_channel] |= peer_info::bw_disk;
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
|
||||||
peer_log(peer_log_alert::info, "DISK", "exceeded disk buffer watermark");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(buffer.get(), data, p.length);
|
|
||||||
incoming_piece(p, std::move(buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void peer_connection::incoming_piece(peer_request const& p, disk_buffer_holder data)
|
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -2636,7 +2603,7 @@ namespace libtorrent
|
||||||
if (m_remote.address().is_v4()
|
if (m_remote.address().is_v4()
|
||||||
&& (m_remote.address().to_v4().to_ulong() & 0xf) == 0)
|
&& (m_remote.address().to_v4().to_ulong() & 0xf) == 0)
|
||||||
{
|
{
|
||||||
data.get()[0] = ~data.get()[0];
|
data[0] = ~data[0];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2654,7 +2621,7 @@ namespace libtorrent
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
for (auto const& e : m_extensions)
|
for (auto const& e : m_extensions)
|
||||||
{
|
{
|
||||||
if (e->on_piece(p, {data.get(), size_t(p.length)}))
|
if (e->on_piece(p, {data, size_t(p.length)}))
|
||||||
{
|
{
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
TORRENT_ASSERT(m_received_in_piece == p.length);
|
TORRENT_ASSERT(m_received_in_piece == p.length);
|
||||||
|
@ -2828,10 +2795,26 @@ namespace libtorrent
|
||||||
|
|
||||||
if (t->is_deleted()) return;
|
if (t->is_deleted()) return;
|
||||||
|
|
||||||
m_disk_thread.async_write(&t->storage(), p, std::move(data)
|
bool const exceeded = m_disk_thread.async_write(&t->storage(), p, data, self()
|
||||||
, std::bind(&peer_connection::on_disk_write_complete
|
, std::bind(&peer_connection::on_disk_write_complete
|
||||||
, self(), _1, p, t));
|
, self(), _1, p, t));
|
||||||
|
|
||||||
|
// every peer is entitled to have two disk blocks allocated at any given
|
||||||
|
// time, regardless of whether the cache size is exceeded or not. If this
|
||||||
|
// was not the case, when the cache size setting is very small, most peers
|
||||||
|
// would be blocked most of the time, because the disk cache would
|
||||||
|
// continuously be in exceeded state. Only rarely would it actually drop
|
||||||
|
// down to 0 and unblock all peers.
|
||||||
|
if (exceeded && m_outstanding_writing_bytes > 0)
|
||||||
|
{
|
||||||
|
if ((m_channel_state[download_channel] & peer_info::bw_disk) == 0)
|
||||||
|
m_counters.inc_stats_counter(counters::num_peers_down_disk);
|
||||||
|
m_channel_state[download_channel] |= peer_info::bw_disk;
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
peer_log(peer_log_alert::info, "DISK", "exceeded disk buffer watermark");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
std::int64_t const write_queue_size = m_counters.inc_stats_counter(
|
std::int64_t const write_queue_size = m_counters.inc_stats_counter(
|
||||||
counters::queued_write_bytes, p.length);
|
counters::queued_write_bytes, p.length);
|
||||||
m_outstanding_writing_bytes += p.length;
|
m_outstanding_writing_bytes += p.length;
|
||||||
|
|
|
@ -6683,23 +6683,11 @@ namespace aux {
|
||||||
m_blocks_to_reclaim.clear();
|
m_blocks_to_reclaim.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
disk_buffer_holder session_impl::allocate_disk_buffer(char const* category)
|
|
||||||
{
|
|
||||||
return m_disk_thread.allocate_disk_buffer(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
void session_impl::free_disk_buffer(char* buf)
|
void session_impl::free_disk_buffer(char* buf)
|
||||||
{
|
{
|
||||||
m_disk_thread.free_disk_buffer(buf);
|
m_disk_thread.free_disk_buffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
disk_buffer_holder session_impl::allocate_disk_buffer(bool& exceeded
|
|
||||||
, std::shared_ptr<disk_observer> o
|
|
||||||
, char const* category)
|
|
||||||
{
|
|
||||||
return m_disk_thread.allocate_disk_buffer(exceeded, o, category);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* session_impl::allocate_buffer()
|
char* session_impl::allocate_buffer()
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
|
|
@ -1213,6 +1213,28 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct piece_refcount
|
||||||
|
{
|
||||||
|
piece_refcount(piece_picker& p, piece_index_t piece)
|
||||||
|
: m_picker(p)
|
||||||
|
, m_piece(piece)
|
||||||
|
{
|
||||||
|
m_picker.inc_refcount(m_piece, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
piece_refcount(piece_refcount const&) = delete;
|
||||||
|
piece_refcount& operator=(piece_refcount const&) = delete;
|
||||||
|
|
||||||
|
~piece_refcount()
|
||||||
|
{
|
||||||
|
m_picker.dec_refcount(m_piece, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
piece_picker& m_picker;
|
||||||
|
piece_index_t m_piece;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: 3 there's some duplication between this function and
|
// TODO: 3 there's some duplication between this function and
|
||||||
// peer_connection::incoming_piece(). is there a way to merge something?
|
// peer_connection::incoming_piece(). is there a way to merge something?
|
||||||
void torrent::add_piece(piece_index_t const piece, char const* data, int const flags)
|
void torrent::add_piece(piece_index_t const piece, char const* data, int const flags)
|
||||||
|
@ -1235,25 +1257,17 @@ namespace libtorrent
|
||||||
peer_request p;
|
peer_request p;
|
||||||
p.piece = piece;
|
p.piece = piece;
|
||||||
p.start = 0;
|
p.start = 0;
|
||||||
picker().inc_refcount(piece, nullptr);
|
piece_refcount refcount{picker(), piece};
|
||||||
for (int i = 0; i < blocks_in_piece; ++i, p.start += block_size())
|
for (int i = 0; i < blocks_in_piece; ++i, p.start += block_size())
|
||||||
{
|
{
|
||||||
if (picker().is_finished(piece_block(piece, i))
|
if (picker().is_finished(piece_block(piece, i))
|
||||||
&& (flags & torrent::overwrite_existing) == 0)
|
&& (flags & torrent::overwrite_existing) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
p.length = (std::min)(piece_size - p.start, int(block_size()));
|
p.length = std::min(piece_size - p.start, int(block_size()));
|
||||||
disk_buffer_holder buffer = m_ses.allocate_disk_buffer("add piece");
|
|
||||||
// out of memory
|
|
||||||
if (!buffer)
|
|
||||||
{
|
|
||||||
picker().dec_refcount(piece, nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::memcpy(buffer.get(), data + p.start, p.length);
|
|
||||||
|
|
||||||
m_stats_counters.inc_stats_counter(counters::queued_write_bytes, p.length);
|
m_stats_counters.inc_stats_counter(counters::queued_write_bytes, p.length);
|
||||||
m_ses.disk_thread().async_write(&storage(), p, std::move(buffer)
|
m_ses.disk_thread().async_write(&storage(), p, data + p.start, nullptr
|
||||||
, std::bind(&torrent::on_disk_write_complete
|
, std::bind(&torrent::on_disk_write_complete
|
||||||
, shared_from_this(), _1, p));
|
, shared_from_this(), _1, p));
|
||||||
|
|
||||||
|
@ -1274,7 +1288,6 @@ namespace libtorrent
|
||||||
verify_piece(p.piece);
|
verify_piece(p.piece);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
picker().dec_refcount(piece, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::on_disk_write_complete(storage_error const& error
|
void torrent::on_disk_write_complete(storage_error const& error
|
||||||
|
|
Loading…
Reference in New Issue