forked from premiere/premiere-libtorrent
optimized disk I/O cache clearing
This commit is contained in:
parent
4ddf87c53e
commit
e07bad0686
|
@ -1,3 +1,4 @@
|
||||||
|
* optimized disk I/O cache clearing
|
||||||
* added feature to ask a torrent if it needs to save its resume data or not
|
* added feature to ask a torrent if it needs to save its resume data or not
|
||||||
* added setting to ignore file modification time when loading resume files
|
* added setting to ignore file modification time when loading resume files
|
||||||
* support more fine-grained torrent states between which peer sources it
|
* support more fine-grained torrent states between which peer sources it
|
||||||
|
|
|
@ -219,6 +219,7 @@ namespace libtorrent
|
||||||
|
|
||||||
char* allocate_buffer(char const* category);
|
char* allocate_buffer(char const* category);
|
||||||
void free_buffer(char* buf);
|
void free_buffer(char* buf);
|
||||||
|
void free_multiple_buffers(char** bufvec, int numbufs);
|
||||||
|
|
||||||
char* allocate_buffers(int blocks, char const* category);
|
char* allocate_buffers(int blocks, char const* category);
|
||||||
void free_buffers(char* buf, int blocks);
|
void free_buffers(char* buf, int blocks);
|
||||||
|
@ -240,6 +241,8 @@ namespace libtorrent
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
void free_buffer_impl(char* buf, mutex::scoped_lock& l);
|
||||||
|
|
||||||
// number of bytes per block. The BitTorrent
|
// number of bytes per block. The BitTorrent
|
||||||
// protocol defines the block size to 16 KiB.
|
// protocol defines the block size to 16 KiB.
|
||||||
const int m_block_size;
|
const int m_block_size;
|
||||||
|
@ -392,6 +395,8 @@ namespace libtorrent
|
||||||
, int options, int num_blocks, mutex::scoped_lock& l);
|
, int options, int num_blocks, mutex::scoped_lock& l);
|
||||||
int cache_read_block(disk_io_job const& j, mutex::scoped_lock& l);
|
int cache_read_block(disk_io_job const& j, mutex::scoped_lock& l);
|
||||||
int free_piece(cached_piece_entry& p, mutex::scoped_lock& l);
|
int free_piece(cached_piece_entry& p, mutex::scoped_lock& l);
|
||||||
|
void drain_piece_bufs(cached_piece_entry& p, std::vector<char*>& buf
|
||||||
|
, mutex::scoped_lock& l);
|
||||||
int try_read_from_cache(disk_io_job const& j, bool& hit);
|
int try_read_from_cache(disk_io_job const& j, bool& hit);
|
||||||
int read_piece_from_cache_and_hash(disk_io_job const& j, sha1_hash& h);
|
int read_piece_from_cache_and_hash(disk_io_job const& j, sha1_hash& h);
|
||||||
int cache_piece(disk_io_job const& j, cache_piece_index_t::iterator& p
|
int cache_piece(disk_io_job const& j, cache_piece_index_t::iterator& p
|
||||||
|
|
|
@ -171,10 +171,30 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void disk_buffer_pool::free_multiple_buffers(char** bufvec, int numbufs)
|
||||||
|
{
|
||||||
|
char** end = bufvec + numbufs;
|
||||||
|
// sort the pointers in order to maximize cache hits
|
||||||
|
std::sort(bufvec, end);
|
||||||
|
|
||||||
|
mutex::scoped_lock l(m_pool_mutex);
|
||||||
|
for (; bufvec != end; ++bufvec)
|
||||||
|
{
|
||||||
|
char* buf = *bufvec;
|
||||||
|
TORRENT_ASSERT(buf);
|
||||||
|
free_buffer_impl(buf, l);;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void disk_buffer_pool::free_buffer(char* buf)
|
void disk_buffer_pool::free_buffer(char* buf)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(buf);
|
|
||||||
mutex::scoped_lock l(m_pool_mutex);
|
mutex::scoped_lock l(m_pool_mutex);
|
||||||
|
free_buffer_impl(buf, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disk_buffer_pool::free_buffer_impl(char* buf, mutex::scoped_lock& l)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(buf);
|
||||||
TORRENT_ASSERT(m_magic == 0x1337);
|
TORRENT_ASSERT(m_magic == 0x1337);
|
||||||
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
||||||
#if defined TORRENT_DISK_STATS || defined TORRENT_STATS
|
#if defined TORRENT_DISK_STATS || defined TORRENT_STATS
|
||||||
|
@ -491,13 +511,32 @@ namespace libtorrent
|
||||||
if (m_settings.explicit_read_cache) return;
|
if (m_settings.explicit_read_cache) return;
|
||||||
|
|
||||||
// flush read cache
|
// flush read cache
|
||||||
|
std::vector<char*> bufs;
|
||||||
cache_lru_index_t& ridx = m_read_pieces.get<1>();
|
cache_lru_index_t& ridx = m_read_pieces.get<1>();
|
||||||
i = ridx.begin();
|
i = ridx.begin();
|
||||||
while (i != ridx.end() && now - i->expire > cut_off)
|
while (i != ridx.end() && now - i->expire > cut_off)
|
||||||
{
|
{
|
||||||
free_piece(const_cast<cached_piece_entry&>(*i), l);
|
drain_piece_bufs(const_cast<cached_piece_entry&>(*i), bufs, l);
|
||||||
ridx.erase(i++);
|
ridx.erase(i++);
|
||||||
}
|
}
|
||||||
|
if (!bufs.empty()) free_multiple_buffers(&bufs[0], bufs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void disk_io_thread::drain_piece_bufs(cached_piece_entry& p, std::vector<char*>& buf
|
||||||
|
, mutex::scoped_lock& l)
|
||||||
|
{
|
||||||
|
int piece_size = p.storage->info()->piece_size(p.piece);
|
||||||
|
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
||||||
|
|
||||||
|
for (int i = 0; i < blocks_in_piece; ++i)
|
||||||
|
{
|
||||||
|
if (p.blocks[i].buf == 0) continue;
|
||||||
|
buf.push_back(p.blocks[i].buf);
|
||||||
|
p.blocks[i].buf = 0;
|
||||||
|
--p.num_blocks;
|
||||||
|
--m_cache_stats.cache_size;
|
||||||
|
--m_cache_stats.read_cache_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the number of blocks that were freed
|
// returns the number of blocks that were freed
|
||||||
|
@ -1752,12 +1791,15 @@ namespace libtorrent
|
||||||
|
|
||||||
mutex::scoped_lock l(m_piece_mutex);
|
mutex::scoped_lock l(m_piece_mutex);
|
||||||
|
|
||||||
|
// build a vector of all the buffers we need to free
|
||||||
|
// and free them all in one go
|
||||||
|
std::vector<char*> buffers;
|
||||||
for (cache_t::iterator i = m_read_pieces.begin();
|
for (cache_t::iterator i = m_read_pieces.begin();
|
||||||
i != m_read_pieces.end();)
|
i != m_read_pieces.end();)
|
||||||
{
|
{
|
||||||
if (i->storage == j.storage)
|
if (i->storage == j.storage)
|
||||||
{
|
{
|
||||||
free_piece(const_cast<cached_piece_entry&>(*i), l);
|
drain_piece_bufs(const_cast<cached_piece_entry&>(*i), buffers, l);
|
||||||
i = m_read_pieces.erase(i);
|
i = m_read_pieces.erase(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1766,6 +1808,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l.unlock();
|
l.unlock();
|
||||||
|
if (!buffers.empty()) free_multiple_buffers(&buffers[0], buffers.size());
|
||||||
release_memory();
|
release_memory();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,6 +177,9 @@ namespace libtorrent
|
||||||
set.low_prio_disk = false;
|
set.low_prio_disk = false;
|
||||||
// one hour expiration
|
// one hour expiration
|
||||||
set.cache_expiry = 60 * 60;
|
set.cache_expiry = 60 * 60;
|
||||||
|
// this is expensive and could add significant
|
||||||
|
// delays when freeing a large number of buffers
|
||||||
|
set.lock_disk_cache = false;
|
||||||
|
|
||||||
// flush write cache based on largest contiguous block
|
// flush write cache based on largest contiguous block
|
||||||
set.disk_cache_algorithm = session_settings::largest_contiguous;
|
set.disk_cache_algorithm = session_settings::largest_contiguous;
|
||||||
|
|
Loading…
Reference in New Issue