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;
|
||||
|
||||
int read_cache_line_size;
|
||||
int write_cache_line_size;
|
||||
};
|
||||
|
||||
``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
|
||||
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
|
||||
===========
|
||||
|
||||
|
|
|
@ -298,12 +298,13 @@ namespace libtorrent
|
|||
, disk_io_job const& j, mutex_t::scoped_lock& l);
|
||||
|
||||
// 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_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
|
||||
, mutex_t::scoped_lock& l);
|
||||
void flush_range(cache_t::iterator i, int start, int end, mutex_t::scoped_lock& l);
|
||||
, mutex_t::scoped_lock& l, int lower_limit = 0);
|
||||
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);
|
||||
|
||||
// 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_piece(disk_io_job const& j, 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 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)
|
||||
, optimize_hashing_for_speed(true)
|
||||
, file_checks_delay_per_block(0)
|
||||
, disk_cache_algorithm(lru)
|
||||
, disk_cache_algorithm(largest_contiguous)
|
||||
, read_cache_line_size(16)
|
||||
, write_cache_line_size(32)
|
||||
{}
|
||||
|
||||
// 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
|
||||
// when reading a block into the read cache
|
||||
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
|
||||
|
|
|
@ -516,7 +516,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
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
|
||||
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);
|
||||
return len;
|
||||
}
|
||||
|
||||
// flushes 'blocks' blocks from the cache
|
||||
void disk_io_thread::flush_cache_blocks(mutex_t::scoped_lock& l
|
||||
, int blocks)
|
||||
int disk_io_thread::flush_cache_blocks(mutex_t::scoped_lock& l
|
||||
, int blocks, cache_t::iterator ignore, int options)
|
||||
{
|
||||
// first look if there are any read cache entries that can
|
||||
// be cleared
|
||||
int ret = 0;
|
||||
int tmp = 0;
|
||||
do {
|
||||
ret = clear_oldest_read_piece(m_read_pieces.end(), l);
|
||||
blocks -= ret;
|
||||
} while (ret > 0 && blocks > 0);
|
||||
tmp = clear_oldest_read_piece(ignore, l);
|
||||
blocks -= tmp;
|
||||
ret += tmp;
|
||||
} while (tmp > 0 && blocks > 0);
|
||||
|
||||
if (options & dont_flush_write_blocks) return ret;
|
||||
|
||||
if (m_settings.disk_cache_algorithm == session_settings::lru)
|
||||
{
|
||||
|
@ -565,8 +570,10 @@ namespace libtorrent
|
|||
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()) return;
|
||||
flush_and_remove(i, l);
|
||||
if (i == m_pieces.end()) return ret;
|
||||
tmp = flush_and_remove(i, l);
|
||||
blocks -= tmp;
|
||||
ret += tmp;
|
||||
}
|
||||
}
|
||||
else if (m_settings.disk_cache_algorithm == session_settings::largest_contiguous)
|
||||
|
@ -577,20 +584,24 @@ namespace libtorrent
|
|||
m_pieces.begin(), m_pieces.end()
|
||||
, bind(&contiguous_blocks, _1)
|
||||
< bind(&contiguous_blocks, _2));
|
||||
if (i == m_pieces.end()) return;
|
||||
blocks -= flush_contiguous_blocks(i, l);
|
||||
if (i == m_pieces.end()) return ret;
|
||||
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)
|
||||
{
|
||||
flush_range(e, 0, INT_MAX, l);
|
||||
int ret = flush_range(e, 0, INT_MAX, l);
|
||||
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)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -662,11 +673,13 @@ namespace libtorrent
|
|||
--m_cache_stats.cache_size;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
for (int i = start; i < end; ++i)
|
||||
{
|
||||
if (p.blocks[i] == 0) continue;
|
||||
free_buffer(p.blocks[i]);
|
||||
p.blocks[i] = 0;
|
||||
++ret;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(buffer_size == 0);
|
||||
|
@ -675,6 +688,7 @@ namespace libtorrent
|
|||
for (int i = start; i < end; ++i)
|
||||
TORRENT_ASSERT(p.blocks[i] == 0);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
// returns -1 on failure
|
||||
|
@ -706,11 +720,6 @@ namespace libtorrent
|
|||
return 0;
|
||||
}
|
||||
|
||||
enum read_options_t
|
||||
{
|
||||
ignore_cache_size = 1
|
||||
};
|
||||
|
||||
// fills a piece with data from disk, returns the total number of bytes
|
||||
// read or -1 if there was an error
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// this function ignores the cache size limit, it will read the entire
|
||||
// piece regardless of the offset in j
|
||||
|
@ -853,7 +836,8 @@ namespace libtorrent
|
|||
int piece_size = j.storage->info()->piece_size(j.piece);
|
||||
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;
|
||||
p.piece = j.piece;
|
||||
|
@ -884,8 +868,12 @@ namespace libtorrent
|
|||
|
||||
int start_block = j.offset / m_block_size;
|
||||
|
||||
if (!make_room(blocks_in_piece - start_block
|
||||
, m_read_pieces.end(), false, l)) return -2;
|
||||
int blocks_to_read = (std::min)(blocks_in_piece - start_block, m_settings.read_cache_line_size);
|
||||
|
||||
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;
|
||||
p.piece = j.piece;
|
||||
|
@ -1054,7 +1042,13 @@ namespace libtorrent
|
|||
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
||||
int end_block = 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);
|
||||
hit = false;
|
||||
if (ret < 0) return ret;
|
||||
|
@ -1465,7 +1459,7 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
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
|
||||
= find_cached_piece(m_pieces, j, l);
|
||||
|
@ -1487,6 +1481,9 @@ namespace libtorrent
|
|||
++m_cache_stats.cache_size;
|
||||
++p->num_blocks;
|
||||
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
|
||||
{
|
||||
|
@ -1507,7 +1504,7 @@ namespace libtorrent
|
|||
holder.release();
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -630,6 +630,7 @@ namespace aux {
|
|||
|| m_settings.file_checks_delay_per_block != s.file_checks_delay_per_block
|
||||
|| m_settings.disk_cache_algorithm != s.disk_cache_algorithm
|
||||
|| 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
|
||||
|| m_settings.lock_disk_cache != s.lock_disk_cache
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue