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

View File

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

View File

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

View File

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

View File

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