clean up some disk cache duplication of logic and added another memory usage optimization for the write cache
This commit is contained in:
parent
6b2148cb39
commit
a89d6cced1
|
@ -3450,6 +3450,7 @@ session_settings
|
||||||
disk_cache_algo_t disk_cache_algorithm;
|
disk_cache_algo_t disk_cache_algorithm;
|
||||||
|
|
||||||
int read_cache_line_size;
|
int read_cache_line_size;
|
||||||
|
int write_cache_line_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
``user_agent`` this is the client identification to the tracker.
|
``user_agent`` this is the client identification to the tracker.
|
||||||
|
@ -3846,6 +3847,10 @@ cache when a read cache miss occurs. Setting this to 0 is essentially
|
||||||
the same thing as disabling read cache. The number of blocks read
|
the same thing as disabling read cache. The number of blocks read
|
||||||
into the read cache is always capped by the piece boundry.
|
into the read cache is always capped by the piece boundry.
|
||||||
|
|
||||||
|
When a piece in the write cache has ``write_cache_line_size`` contiguous
|
||||||
|
blocks in it, they will be flushed. Setting this to 1 effectively
|
||||||
|
disables the write cache.
|
||||||
|
|
||||||
pe_settings
|
pe_settings
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
|
@ -298,12 +298,13 @@ namespace libtorrent
|
||||||
, disk_io_job const& j, mutex_t::scoped_lock& l);
|
, disk_io_job const& j, mutex_t::scoped_lock& l);
|
||||||
|
|
||||||
// write cache operations
|
// write cache operations
|
||||||
void flush_cache_blocks(mutex_t::scoped_lock& l, int blocks);
|
enum options_t { dont_flush_write_blocks = 1, ignore_cache_size = 2 };
|
||||||
|
int flush_cache_blocks(mutex_t::scoped_lock& l, int blocks, cache_t::iterator ignore, int options = 0);
|
||||||
void flush_expired_pieces();
|
void flush_expired_pieces();
|
||||||
void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
|
int flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
|
||||||
int flush_contiguous_blocks(disk_io_thread::cache_t::iterator e
|
int flush_contiguous_blocks(disk_io_thread::cache_t::iterator e
|
||||||
, mutex_t::scoped_lock& l);
|
, mutex_t::scoped_lock& l, int lower_limit = 0);
|
||||||
void flush_range(cache_t::iterator i, int start, int end, mutex_t::scoped_lock& l);
|
int flush_range(cache_t::iterator i, int start, int end, mutex_t::scoped_lock& l);
|
||||||
int cache_block(disk_io_job& j, mutex_t::scoped_lock& l);
|
int cache_block(disk_io_job& j, mutex_t::scoped_lock& l);
|
||||||
|
|
||||||
// read cache operations
|
// read cache operations
|
||||||
|
@ -314,10 +315,6 @@ namespace libtorrent
|
||||||
int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
|
int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
|
||||||
int cache_read_piece(disk_io_job const& j, mutex_t::scoped_lock& l);
|
int cache_read_piece(disk_io_job const& j, mutex_t::scoped_lock& l);
|
||||||
int free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
|
int free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
|
||||||
bool make_room(int num_blocks
|
|
||||||
, cache_t::iterator ignore
|
|
||||||
, bool flush_write_cache
|
|
||||||
, mutex_t::scoped_lock& l);
|
|
||||||
int try_read_from_cache(disk_io_job const& j);
|
int try_read_from_cache(disk_io_job const& j);
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -167,8 +167,9 @@ namespace libtorrent
|
||||||
, send_socket_buffer_size(0)
|
, send_socket_buffer_size(0)
|
||||||
, optimize_hashing_for_speed(true)
|
, optimize_hashing_for_speed(true)
|
||||||
, file_checks_delay_per_block(0)
|
, file_checks_delay_per_block(0)
|
||||||
, disk_cache_algorithm(lru)
|
, disk_cache_algorithm(largest_contiguous)
|
||||||
, read_cache_line_size(16)
|
, read_cache_line_size(16)
|
||||||
|
, write_cache_line_size(32)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// this is the user agent that will be sent to the tracker
|
// this is the user agent that will be sent to the tracker
|
||||||
|
@ -581,6 +582,11 @@ namespace libtorrent
|
||||||
// the number of blocks that will be read ahead
|
// the number of blocks that will be read ahead
|
||||||
// when reading a block into the read cache
|
// when reading a block into the read cache
|
||||||
int read_cache_line_size;
|
int read_cache_line_size;
|
||||||
|
|
||||||
|
// whenever a contiguous range of this many
|
||||||
|
// blocks is found in the write cache, it
|
||||||
|
// is flushed immediately
|
||||||
|
int write_cache_line_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
|
|
|
@ -516,7 +516,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
int disk_io_thread::flush_contiguous_blocks(disk_io_thread::cache_t::iterator e
|
int disk_io_thread::flush_contiguous_blocks(disk_io_thread::cache_t::iterator e
|
||||||
, mutex_t::scoped_lock& l)
|
, mutex_t::scoped_lock& l, int lower_limit)
|
||||||
{
|
{
|
||||||
// first find the largest range of contiguous blocks
|
// first find the largest range of contiguous blocks
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
@ -540,22 +540,27 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_range(e, pos, pos + len, l);
|
if (len < lower_limit) return 0;
|
||||||
|
len = flush_range(e, pos, pos + len, l);
|
||||||
if (e->num_blocks == 0) m_pieces.erase(e);
|
if (e->num_blocks == 0) m_pieces.erase(e);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// flushes 'blocks' blocks from the cache
|
// flushes 'blocks' blocks from the cache
|
||||||
void disk_io_thread::flush_cache_blocks(mutex_t::scoped_lock& l
|
int disk_io_thread::flush_cache_blocks(mutex_t::scoped_lock& l
|
||||||
, int blocks)
|
, int blocks, cache_t::iterator ignore, int options)
|
||||||
{
|
{
|
||||||
// first look if there are any read cache entries that can
|
// first look if there are any read cache entries that can
|
||||||
// be cleared
|
// be cleared
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int tmp = 0;
|
||||||
do {
|
do {
|
||||||
ret = clear_oldest_read_piece(m_read_pieces.end(), l);
|
tmp = clear_oldest_read_piece(ignore, l);
|
||||||
blocks -= ret;
|
blocks -= tmp;
|
||||||
} while (ret > 0 && blocks > 0);
|
ret += tmp;
|
||||||
|
} while (tmp > 0 && blocks > 0);
|
||||||
|
|
||||||
|
if (options & dont_flush_write_blocks) return ret;
|
||||||
|
|
||||||
if (m_settings.disk_cache_algorithm == session_settings::lru)
|
if (m_settings.disk_cache_algorithm == session_settings::lru)
|
||||||
{
|
{
|
||||||
|
@ -565,8 +570,10 @@ namespace libtorrent
|
||||||
m_pieces.begin(), m_pieces.end()
|
m_pieces.begin(), m_pieces.end()
|
||||||
, bind(&cached_piece_entry::last_use, _1)
|
, bind(&cached_piece_entry::last_use, _1)
|
||||||
< bind(&cached_piece_entry::last_use, _2));
|
< bind(&cached_piece_entry::last_use, _2));
|
||||||
if (i == m_pieces.end()) return;
|
if (i == m_pieces.end()) return ret;
|
||||||
flush_and_remove(i, l);
|
tmp = flush_and_remove(i, l);
|
||||||
|
blocks -= tmp;
|
||||||
|
ret += tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_settings.disk_cache_algorithm == session_settings::largest_contiguous)
|
else if (m_settings.disk_cache_algorithm == session_settings::largest_contiguous)
|
||||||
|
@ -577,20 +584,24 @@ namespace libtorrent
|
||||||
m_pieces.begin(), m_pieces.end()
|
m_pieces.begin(), m_pieces.end()
|
||||||
, bind(&contiguous_blocks, _1)
|
, bind(&contiguous_blocks, _1)
|
||||||
< bind(&contiguous_blocks, _2));
|
< bind(&contiguous_blocks, _2));
|
||||||
if (i == m_pieces.end()) return;
|
if (i == m_pieces.end()) return ret;
|
||||||
blocks -= flush_contiguous_blocks(i, l);
|
tmp = flush_contiguous_blocks(i, l);
|
||||||
|
blocks -= tmp;
|
||||||
|
ret += tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_io_thread::flush_and_remove(disk_io_thread::cache_t::iterator e
|
int disk_io_thread::flush_and_remove(disk_io_thread::cache_t::iterator e
|
||||||
, mutex_t::scoped_lock& l)
|
, mutex_t::scoped_lock& l)
|
||||||
{
|
{
|
||||||
flush_range(e, 0, INT_MAX, l);
|
int ret = flush_range(e, 0, INT_MAX, l);
|
||||||
m_pieces.erase(e);
|
m_pieces.erase(e);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_io_thread::flush_range(disk_io_thread::cache_t::iterator e
|
int disk_io_thread::flush_range(disk_io_thread::cache_t::iterator e
|
||||||
, int start, int end, mutex_t::scoped_lock& l)
|
, int start, int end, mutex_t::scoped_lock& l)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -662,11 +673,13 @@ namespace libtorrent
|
||||||
--m_cache_stats.cache_size;
|
--m_cache_stats.cache_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
for (int i = start; i < end; ++i)
|
for (int i = start; i < end; ++i)
|
||||||
{
|
{
|
||||||
if (p.blocks[i] == 0) continue;
|
if (p.blocks[i] == 0) continue;
|
||||||
free_buffer(p.blocks[i]);
|
free_buffer(p.blocks[i]);
|
||||||
p.blocks[i] = 0;
|
p.blocks[i] = 0;
|
||||||
|
++ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(buffer_size == 0);
|
TORRENT_ASSERT(buffer_size == 0);
|
||||||
|
@ -675,6 +688,7 @@ namespace libtorrent
|
||||||
for (int i = start; i < end; ++i)
|
for (int i = start; i < end; ++i)
|
||||||
TORRENT_ASSERT(p.blocks[i] == 0);
|
TORRENT_ASSERT(p.blocks[i] == 0);
|
||||||
#endif
|
#endif
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns -1 on failure
|
// returns -1 on failure
|
||||||
|
@ -706,11 +720,6 @@ namespace libtorrent
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum read_options_t
|
|
||||||
{
|
|
||||||
ignore_cache_size = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// fills a piece with data from disk, returns the total number of bytes
|
// fills a piece with data from disk, returns the total number of bytes
|
||||||
// read or -1 if there was an error
|
// read or -1 if there was an error
|
||||||
int disk_io_thread::read_into_piece(cached_piece_entry& p, int start_block
|
int disk_io_thread::read_into_piece(cached_piece_entry& p, int start_block
|
||||||
|
@ -817,32 +826,6 @@ namespace libtorrent
|
||||||
return (ret != buffer_size) ? -1 : ret;
|
return (ret != buffer_size) ? -1 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool disk_io_thread::make_room(int num_blocks
|
|
||||||
, cache_t::iterator ignore
|
|
||||||
, bool flush_write_cache
|
|
||||||
, mutex_t::scoped_lock& l)
|
|
||||||
{
|
|
||||||
while (m_settings.cache_size - in_use() < num_blocks)
|
|
||||||
{
|
|
||||||
// there's not enough room in the cache, clear a piece
|
|
||||||
// from the read cache
|
|
||||||
if (!clear_oldest_read_piece(ignore, l)) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try flushing write cache
|
|
||||||
while (flush_write_cache && m_settings.cache_size - in_use() < num_blocks)
|
|
||||||
{
|
|
||||||
cache_t::iterator i = std::min_element(
|
|
||||||
m_pieces.begin(), m_pieces.end()
|
|
||||||
, bind(&cached_piece_entry::last_use, _1)
|
|
||||||
< bind(&cached_piece_entry::last_use, _2));
|
|
||||||
if (i == m_pieces.end()) break;
|
|
||||||
flush_and_remove(i, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_settings.cache_size - in_use() >= num_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns -1 on read error, -2 on out of memory error or the number of bytes read
|
// returns -1 on read error, -2 on out of memory error or the number of bytes read
|
||||||
// this function ignores the cache size limit, it will read the entire
|
// this function ignores the cache size limit, it will read the entire
|
||||||
// piece regardless of the offset in j
|
// piece regardless of the offset in j
|
||||||
|
@ -853,7 +836,8 @@ namespace libtorrent
|
||||||
int piece_size = j.storage->info()->piece_size(j.piece);
|
int piece_size = j.storage->info()->piece_size(j.piece);
|
||||||
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
||||||
|
|
||||||
make_room(blocks_in_piece, m_read_pieces.end(), true, l);
|
if (in_use() + blocks_in_piece > m_settings.cache_size)
|
||||||
|
flush_cache_blocks(l, in_use() + blocks_in_piece - m_settings.cache_size, m_read_pieces.end());
|
||||||
|
|
||||||
cached_piece_entry p;
|
cached_piece_entry p;
|
||||||
p.piece = j.piece;
|
p.piece = j.piece;
|
||||||
|
@ -884,8 +868,12 @@ namespace libtorrent
|
||||||
|
|
||||||
int start_block = j.offset / m_block_size;
|
int start_block = j.offset / m_block_size;
|
||||||
|
|
||||||
if (!make_room(blocks_in_piece - start_block
|
int blocks_to_read = (std::min)(blocks_in_piece - start_block, m_settings.read_cache_line_size);
|
||||||
, m_read_pieces.end(), false, l)) return -2;
|
|
||||||
|
if (in_use() + blocks_to_read > m_settings.cache_size)
|
||||||
|
if (flush_cache_blocks(l, in_use() + blocks_to_read - m_settings.cache_size
|
||||||
|
, m_read_pieces.end(), dont_flush_write_blocks) == 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
cached_piece_entry p;
|
cached_piece_entry p;
|
||||||
p.piece = j.piece;
|
p.piece = j.piece;
|
||||||
|
@ -1054,7 +1042,13 @@ namespace libtorrent
|
||||||
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
||||||
int end_block = block;
|
int end_block = block;
|
||||||
while (end_block < blocks_in_piece && p->blocks[end_block] == 0) ++end_block;
|
while (end_block < blocks_in_piece && p->blocks[end_block] == 0) ++end_block;
|
||||||
if (!make_room(end_block - block, p, false, l)) return -2;
|
|
||||||
|
int blocks_to_read = end_block - block;
|
||||||
|
if (in_use() + blocks_to_read > m_settings.cache_size)
|
||||||
|
if (flush_cache_blocks(l, in_use() + blocks_to_read - m_settings.cache_size
|
||||||
|
, p, dont_flush_write_blocks) == 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
int ret = read_into_piece(*p, block, 0, l);
|
int ret = read_into_piece(*p, block, 0, l);
|
||||||
hit = false;
|
hit = false;
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
|
@ -1465,7 +1459,7 @@ namespace libtorrent
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
if (in_use() >= m_settings.cache_size)
|
if (in_use() >= m_settings.cache_size)
|
||||||
flush_cache_blocks(l, in_use() - m_settings.cache_size + 1);
|
flush_cache_blocks(l, in_use() - m_settings.cache_size + 1, m_read_pieces.end());
|
||||||
|
|
||||||
cache_t::iterator p
|
cache_t::iterator p
|
||||||
= find_cached_piece(m_pieces, j, l);
|
= find_cached_piece(m_pieces, j, l);
|
||||||
|
@ -1487,6 +1481,9 @@ namespace libtorrent
|
||||||
++m_cache_stats.cache_size;
|
++m_cache_stats.cache_size;
|
||||||
++p->num_blocks;
|
++p->num_blocks;
|
||||||
p->last_use = time_now();
|
p->last_use = time_now();
|
||||||
|
// we might just have created a contiguous range
|
||||||
|
// that meets the requirement to be flushed. try it
|
||||||
|
flush_contiguous_blocks(p, l, m_settings.write_cache_line_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1507,7 +1504,7 @@ namespace libtorrent
|
||||||
holder.release();
|
holder.release();
|
||||||
|
|
||||||
if (in_use() > m_settings.cache_size)
|
if (in_use() > m_settings.cache_size)
|
||||||
flush_cache_blocks(l, in_use() - m_settings.cache_size);
|
flush_cache_blocks(l, in_use() - m_settings.cache_size, m_read_pieces.end());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -630,6 +630,7 @@ namespace aux {
|
||||||
|| m_settings.file_checks_delay_per_block != s.file_checks_delay_per_block
|
|| m_settings.file_checks_delay_per_block != s.file_checks_delay_per_block
|
||||||
|| m_settings.disk_cache_algorithm != s.disk_cache_algorithm
|
|| m_settings.disk_cache_algorithm != s.disk_cache_algorithm
|
||||||
|| m_settings.read_cache_line_size != s.read_cache_line_size
|
|| m_settings.read_cache_line_size != s.read_cache_line_size
|
||||||
|
|| m_settings.write_cache_line_size != s.write_cache_line_size
|
||||||
#ifndef TORRENT_DISABLE_MLOCK
|
#ifndef TORRENT_DISABLE_MLOCK
|
||||||
|| m_settings.lock_disk_cache != s.lock_disk_cache
|
|| m_settings.lock_disk_cache != s.lock_disk_cache
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue