diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 0a834bcf6..5269507e1 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -743,6 +743,7 @@ namespace libtorrent { INVARIANT_CHECK; TORRENT_ASSERT(find_cached_piece(m_pieces, j, l) == m_pieces.end()); + TORRENT_ASSERT((j.offset & (m_block_size-1)) == 0); cached_piece_entry p; #ifdef TORRENT_DISK_STATS @@ -1088,25 +1089,35 @@ namespace libtorrent int block_offset = j.offset & (m_block_size-1); int buffer_offset = 0; int size = j.buffer_size; - if (p->blocks[block] == 0) + int min_blocks_to_read = block_offset > 0 ? 2 : 1; + TORRENT_ASSERT(size <= m_block_size); + int start_block = block; + if (p->blocks[start_block] != 0 && min_blocks_to_read > 1) + ++start_block; + // if block_offset > 0, we need to read two blocks, and then + // copy parts of both, because it's not aligned to the block + // boundaries + if (p->blocks[start_block] == 0) { int piece_size = j.storage->info()->piece_size(j.piece); int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; - int end_block = block; + int end_block = start_block; while (end_block < blocks_in_piece && p->blocks[end_block] == 0) ++end_block; int blocks_to_read = end_block - block; blocks_to_read = (std::min)(blocks_to_read, (std::max)((m_settings.cache_size + m_cache_stats.read_cache_size - in_use())/2, 3)); blocks_to_read = (std::min)(blocks_to_read, m_settings.read_cache_line_size); + blocks_to_read = (std::max)(blocks_to_read, min_blocks_to_read); 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; - size = read_into_piece(*p, block, 0, blocks_to_read, l); + int ret = read_into_piece(*p, block, 0, blocks_to_read, l); hit = false; - if (size < 0) return size; + if (ret < 0) return ret; + if (ret < size + block_offset) return -2; TORRENT_ASSERT(p->blocks[block]); } diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 8fa654915..89798fa30 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -49,7 +49,8 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; using namespace boost::filesystem; -const int piece_size = 16 * 1024; +const int piece_size = 16 * 1024 * 16; +const int block_size = 16 * 1024; const int half = piece_size / 2; @@ -92,6 +93,19 @@ void on_check_files(int ret, disk_io_job const& j, bool* done) } } +void on_read(int ret, disk_io_job const& j, bool* done) +{ + std::cerr << "on_read ret: " << ret; + *done = true; + + if (ret < 0) + { + std::cerr << j.error.message() << std::endl; + std::cerr << j.error_file << std::endl; + + } +} + void on_move_storage(int ret, disk_io_job const& j, std::string path) { std::cerr << "on_move_storage ret: " << ret << " path: " << j.str << std::endl; @@ -206,6 +220,18 @@ void run_storage_tests(boost::intrusive_ptr info ios.run_one(ec); } + done = false; + peer_request r; + r.piece = 0; + r.start = 10; + r.length = 16 * 1024; + pm->async_read(r, boost::bind(&on_read, _1, _2, &done)); + while (!done) + { + ios.reset(); + ios.run_one(ec); + } + // test rename_file remove(test_path / "part0"); TEST_CHECK(exists(test_path / "temp_storage/test1.tmp")); @@ -246,15 +272,14 @@ void run_storage_tests(boost::intrusive_ptr info TEST_CHECK(!exists(test_path / "temp_storage2/temp_storage")); TEST_CHECK(!exists(test_path / "temp_storage2/part0")); - peer_request r; r.piece = 0; r.start = 0; - r.length = piece_size; - pm->async_read(r, bind(&on_read_piece, _1, _2, piece0, piece_size)); + r.length = block_size; + pm->async_read(r, bind(&on_read_piece, _1, _2, piece0, block_size)); r.piece = 1; - pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, piece_size)); + pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, block_size)); r.piece = 2; - pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size)); + pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, block_size)); pm->async_release_files(none); pm->async_rename_file(0, "temp_storage/test1.tmp", none);