clean up some disk cache duplication of logic and added another memory usage optimization for the write cache

This commit is contained in:
Arvid Norberg 2009-05-24 00:12:53 +00:00
parent 6b2148cb39
commit a89d6cced1
5 changed files with 66 additions and 60 deletions

View File

@ -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
=========== ===========

View File

@ -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);

View File

@ -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

View File

@ -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;
} }

View File

@ -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