diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 3bc09489e..c6b383be2 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -344,6 +344,8 @@ namespace libtorrent ptime expire; // the number of blocks in the cache for this piece int num_blocks; + // used to determine if this piece should be flushed + int num_contiguous_blocks; // the pointers to the block data boost::shared_array blocks; diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index b08c4c43a..a51d2809e 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -639,8 +639,8 @@ namespace libtorrent { cache_lru_index_t::iterator i = std::max_element(idx.begin(), idx.end() - , boost::bind(&contiguous_blocks, _1) - < boost::bind(&contiguous_blocks, _2)); + , boost::bind(&disk_io_thread::cached_piece_entry::num_contiguous_blocks, _1) + < boost::bind(&disk_io_thread::cached_piece_entry::num_contiguous_blocks, _2)); if (i == idx.end()) return ret; tmp = flush_contiguous_blocks(const_cast(*i), l); if (i->num_blocks == 0) idx.erase(i); @@ -758,6 +758,7 @@ namespace libtorrent if (num_write_calls > 0) { m_write_time.add_sample(total_microseconds(done - write_start) / num_write_calls); + p.num_contiguous_blocks = contiguous_blocks(p); } TORRENT_ASSERT(buffer_size == 0); @@ -795,6 +796,7 @@ namespace libtorrent p.storage = j.storage; p.expire = time_now() + seconds(j.cache_min_time); p.num_blocks = 1; + p.num_contiguous_blocks = 1; p.blocks.reset(new (std::nothrow) cached_block_entry[blocks_in_piece]); if (!p.blocks) return -1; int block = j.offset / m_block_size; @@ -979,6 +981,7 @@ namespace libtorrent p.storage = j.storage; p.expire = time_now() + seconds(j.cache_min_time); p.num_blocks = 0; + p.num_contiguous_blocks = 0; p.blocks.reset(new (std::nothrow) cached_block_entry[blocks_in_piece]); if (!p.blocks) return -1; @@ -1000,6 +1003,7 @@ namespace libtorrent { cached_piece_entry const& p = *i; TORRENT_ASSERT(p.blocks); + TORRENT_ASSERT(p.num_contiguous_blocks == contiguous_blocks(p)); TORRENT_ASSERT(p.storage); int piece_size = p.storage->info()->piece_size(p.piece); @@ -1100,6 +1104,7 @@ namespace libtorrent pe.storage = j.storage; pe.expire = time_now() + seconds(j.cache_min_time); pe.num_blocks = 0; + pe.num_contiguous_blocks = 0; pe.blocks.reset(new (std::nothrow) cached_block_entry[blocks_in_piece]); if (!pe.blocks) return -1; ret = read_into_piece(pe, 0, options, INT_MAX, l); @@ -2048,8 +2053,11 @@ namespace libtorrent int block = j.offset / m_block_size; TORRENT_ASSERT(j.buffer); TORRENT_ASSERT(j.buffer_size <= m_block_size); + int piece_size = j.storage->info()->piece_size(j.piece); + int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; if (p != idx.end()) { + bool recalc_contiguous = false; TORRENT_ASSERT(p->blocks[block].buf == 0); if (p->blocks[block].buf) { @@ -2057,6 +2065,13 @@ namespace libtorrent --m_cache_stats.cache_size; --const_cast(*p).num_blocks; } + else if ((block > 0 && p->blocks[block-1].buf) || (block < blocks_in_piece-1 && p->blocks[block+1].buf)) + { + // update the contiguous blocks counter for this piece. Only if it has + // an adjacent block. If it doesn't, we already know it couldn't have + // increased the largest contiguous block span in this piece + recalc_contiguous = true; + } p->blocks[block].buf = j.buffer; p->blocks[block].callback.swap(j.callback); #ifdef TORRENT_DISK_STATS @@ -2064,6 +2079,10 @@ namespace libtorrent #endif ++m_cache_stats.cache_size; ++const_cast(*p).num_blocks; + if (recalc_contiguous) + { + const_cast(*p).num_contiguous_blocks = contiguous_blocks(*p); + } idx.modify(p, update_last_use(j.cache_min_time)); // we might just have created a contiguous range // that meets the requirement to be flushed. try it