factor out some common storage utilities out of storage.cpp (#1515)
factor out some common storage utilities out of storage.cpp
This commit is contained in:
parent
3b4867046f
commit
3d06371f31
|
@ -86,6 +86,7 @@ set(sources
|
||||||
stat
|
stat
|
||||||
stat_cache
|
stat_cache
|
||||||
storage
|
storage
|
||||||
|
storage_utils
|
||||||
time
|
time
|
||||||
timestamp_history
|
timestamp_history
|
||||||
torrent
|
torrent
|
||||||
|
|
1
Jamfile
1
Jamfile
|
@ -609,6 +609,7 @@ SOURCES =
|
||||||
socks5_stream
|
socks5_stream
|
||||||
stat
|
stat
|
||||||
storage
|
storage
|
||||||
|
storage_utils
|
||||||
torrent
|
torrent
|
||||||
torrent_handle
|
torrent_handle
|
||||||
torrent_info
|
torrent_info
|
||||||
|
|
|
@ -862,7 +862,7 @@ void generate_data(char const* path, torrent_info const& ti)
|
||||||
{
|
{
|
||||||
generate_block(piece, i, j, 0x4000);
|
generate_block(piece, i, j, 0x4000);
|
||||||
int const left_in_piece = ti.piece_size(i) - j;
|
int const left_in_piece = ti.piece_size(i) - j;
|
||||||
file::iovec_t const b = { piece, size_t(std::min(left_in_piece, 0x4000))};
|
iovec_t const b = { piece, size_t(std::min(left_in_piece, 0x4000))};
|
||||||
storage_error error;
|
storage_error error;
|
||||||
st->writev(b, i, j, 0, error);
|
st->writev(b, i, j, 0, error);
|
||||||
if (error)
|
if (error)
|
||||||
|
|
|
@ -187,6 +187,7 @@ nobase_include_HEADERS = \
|
||||||
aux_/win_crypto_provider.hpp \
|
aux_/win_crypto_provider.hpp \
|
||||||
aux_/win_util.hpp \
|
aux_/win_util.hpp \
|
||||||
aux_/non_owning_handle.hpp \
|
aux_/non_owning_handle.hpp \
|
||||||
|
aux_/storage_utils.hpp \
|
||||||
\
|
\
|
||||||
extensions/smart_ban.hpp \
|
extensions/smart_ban.hpp \
|
||||||
extensions/ut_metadata.hpp \
|
extensions/ut_metadata.hpp \
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2003-2016, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_STORAGE_UTILS_HPP_INCLUDE
|
||||||
|
#define TORRENT_STORAGE_UTILS_HPP_INCLUDE
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/span.hpp"
|
||||||
|
#include "libtorrent/units.hpp"
|
||||||
|
|
||||||
|
#ifndef TORRENT_WINDOWS
|
||||||
|
#include <sys/uio.h> // for iovec
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
class file_storage;
|
||||||
|
struct storage_error;
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
struct iovec_t
|
||||||
|
{
|
||||||
|
void* iov_base;
|
||||||
|
size_t iov_len;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
using iovec_t = ::iovec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TORRENT_EXTRA_EXPORT int copy_bufs(span<iovec_t const> bufs, int bytes, span<iovec_t> target);
|
||||||
|
TORRENT_EXTRA_EXPORT span<iovec_t> advance_bufs(span<iovec_t> bufs, int bytes);
|
||||||
|
|
||||||
|
// this identifies a read or write operation so that readwritev() knows
|
||||||
|
// what to do when it's actually touching the file
|
||||||
|
struct fileop
|
||||||
|
{
|
||||||
|
virtual int file_op(file_index_t const file_index, std::int64_t const file_offset
|
||||||
|
, span<iovec_t const> bufs, storage_error& ec) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~fileop() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// this function is responsible for turning read and write operations in the
|
||||||
|
// torrent space (pieces) into read and write operations in the filesystem
|
||||||
|
// space (files on disk).
|
||||||
|
TORRENT_EXTRA_EXPORT int readwritev(file_storage const& files
|
||||||
|
, span<iovec_t const> bufs, piece_index_t piece, int offset
|
||||||
|
, fileop& op, storage_error& ec);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -424,7 +424,7 @@ namespace libtorrent
|
||||||
cached_piece_entry* add_dirty_block(disk_io_job* j);
|
cached_piece_entry* add_dirty_block(disk_io_job* j);
|
||||||
|
|
||||||
enum { blocks_inc_refcount = 1 };
|
enum { blocks_inc_refcount = 1 };
|
||||||
void insert_blocks(cached_piece_entry* pe, int block, span<file::iovec_t const> iov
|
void insert_blocks(cached_piece_entry* pe, int block, span<iovec_t const> iov
|
||||||
, disk_io_job* j, int flags = 0);
|
, disk_io_job* j, int flags = 0);
|
||||||
|
|
||||||
#if TORRENT_USE_INVARIANT_CHECKS
|
#if TORRENT_USE_INVARIANT_CHECKS
|
||||||
|
|
|
@ -80,8 +80,8 @@ namespace libtorrent
|
||||||
void free_buffer(char* buf);
|
void free_buffer(char* buf);
|
||||||
void free_multiple_buffers(span<char*> bufvec);
|
void free_multiple_buffers(span<char*> bufvec);
|
||||||
|
|
||||||
int allocate_iovec(span<file::iovec_t> iov);
|
int allocate_iovec(span<iovec_t> iov);
|
||||||
void free_iovec(span<file::iovec_t const> iov);
|
void free_iovec(span<iovec_t const> iov);
|
||||||
|
|
||||||
int block_size() const { return m_block_size; }
|
int block_size() const { return m_block_size; }
|
||||||
|
|
||||||
|
|
|
@ -443,8 +443,8 @@ namespace libtorrent
|
||||||
|
|
||||||
// low level flush operations, used by flush_range
|
// low level flush operations, used by flush_range
|
||||||
int build_iovec(cached_piece_entry* pe, int start, int end
|
int build_iovec(cached_piece_entry* pe, int start, int end
|
||||||
, span<file::iovec_t> iov, span<int> flushing, int block_base_index = 0);
|
, span<iovec_t> iov, span<int> flushing, int block_base_index = 0);
|
||||||
void flush_iovec(cached_piece_entry* pe, span<file::iovec_t const> iov, span<int const> flushing
|
void flush_iovec(cached_piece_entry* pe, span<iovec_t const> iov, span<int const> flushing
|
||||||
, int num_blocks, storage_error& error);
|
, int num_blocks, storage_error& error);
|
||||||
void iovec_flushed(cached_piece_entry* pe
|
void iovec_flushed(cached_piece_entry* pe
|
||||||
, int* flushing, int num_blocks, int block_offset
|
, int* flushing, int num_blocks, int block_offset
|
||||||
|
|
|
@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
#include "libtorrent/string_view.hpp"
|
#include "libtorrent/string_view.hpp"
|
||||||
#include "libtorrent/span.hpp"
|
#include "libtorrent/span.hpp"
|
||||||
|
#include "libtorrent/aux_/storage_utils.hpp"
|
||||||
|
|
||||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
|
|
||||||
|
@ -265,22 +266,6 @@ namespace libtorrent
|
||||||
attribute_mask = attribute_hidden | attribute_executable
|
attribute_mask = attribute_hidden | attribute_executable
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
|
||||||
struct iovec_t
|
|
||||||
{
|
|
||||||
void* iov_base;
|
|
||||||
size_t iov_len;
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
using iovec_t = iovec;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TORRENT_SOLARIS
|
|
||||||
using iovec_base_t = char*;
|
|
||||||
#else
|
|
||||||
using iovec_base_t = void*;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
file();
|
file();
|
||||||
file(std::string const& p, int m, error_code& ec);
|
file(std::string const& p, int m, error_code& ec);
|
||||||
~file();
|
~file();
|
||||||
|
@ -315,7 +300,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT int bufs_size(span<file::iovec_t const> bufs);
|
TORRENT_EXTRA_EXPORT int bufs_size(span<iovec_t const> bufs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,8 @@ namespace libtorrent
|
||||||
part_file(std::string const& path, std::string const& name, int num_pieces, int piece_size);
|
part_file(std::string const& path, std::string const& name, int num_pieces, int piece_size);
|
||||||
~part_file();
|
~part_file();
|
||||||
|
|
||||||
int writev(span<file::iovec_t const> bufs, piece_index_t piece, int offset, error_code& ec);
|
int writev(span<iovec_t const> bufs, piece_index_t piece, int offset, error_code& ec);
|
||||||
int readv(span<file::iovec_t const> bufs, piece_index_t piece, int offset, error_code& ec);
|
int readv(span<iovec_t const> bufs, piece_index_t piece, int offset, error_code& ec);
|
||||||
|
|
||||||
// free the slot the given piece is stored in. We no longer need to store this
|
// free the slot the given piece is stored in. We no longer need to store this
|
||||||
// piece in the part file
|
// piece in the part file
|
||||||
|
|
|
@ -146,9 +146,7 @@ namespace libtorrent
|
||||||
struct cached_piece_entry;
|
struct cached_piece_entry;
|
||||||
struct add_torrent_params;
|
struct add_torrent_params;
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT int copy_bufs(span<file::iovec_t const> bufs, int bytes, span<file::iovec_t> target);
|
TORRENT_EXTRA_EXPORT void clear_bufs(span<iovec_t const> bufs);
|
||||||
TORRENT_EXTRA_EXPORT span<file::iovec_t> advance_bufs(span<file::iovec_t> bufs, int bytes);
|
|
||||||
TORRENT_EXTRA_EXPORT void clear_bufs(span<file::iovec_t const> bufs);
|
|
||||||
|
|
||||||
struct disk_io_thread;
|
struct disk_io_thread;
|
||||||
|
|
||||||
|
@ -297,7 +295,7 @@ namespace libtorrent
|
||||||
// These functions should read and write the data in or to the given
|
// These functions should read and write the data in or to the given
|
||||||
// ``piece`` at the given ``offset``. It should read or write
|
// ``piece`` at the given ``offset``. It should read or write
|
||||||
// ``num_bufs`` buffers sequentially, where the size of each buffer is
|
// ``num_bufs`` buffers sequentially, where the size of each buffer is
|
||||||
// specified in the buffer array ``bufs``. The file::iovec_t type has the
|
// specified in the buffer array ``bufs``. The iovec_t type has the
|
||||||
// following members::
|
// following members::
|
||||||
//
|
//
|
||||||
// struct iovec_t { void* iov_base; size_t iov_len; };
|
// struct iovec_t { void* iov_base; size_t iov_len; };
|
||||||
|
@ -323,9 +321,9 @@ namespace libtorrent
|
||||||
// The number of bytes read or written should be returned, or -1 on
|
// The number of bytes read or written should be returned, or -1 on
|
||||||
// error. If there's an error, the ``storage_error`` must be filled out
|
// error. If there's an error, the ``storage_error`` must be filled out
|
||||||
// to represent the error that occurred.
|
// to represent the error that occurred.
|
||||||
virtual int readv(span<file::iovec_t const> bufs
|
virtual int readv(span<iovec_t const> bufs
|
||||||
, piece_index_t piece, int offset, int flags, storage_error& ec) = 0;
|
, piece_index_t piece, int offset, int flags, storage_error& ec) = 0;
|
||||||
virtual int writev(span<file::iovec_t const> bufs
|
virtual int writev(span<iovec_t const> bufs
|
||||||
, piece_index_t piece, int offset, int flags, storage_error& ec) = 0;
|
, piece_index_t piece, int offset, int flags, storage_error& ec) = 0;
|
||||||
|
|
||||||
// This function is called when first checking (or re-checking) the
|
// This function is called when first checking (or re-checking) the
|
||||||
|
@ -514,9 +512,9 @@ namespace libtorrent
|
||||||
, storage_error& error) override;
|
, storage_error& error) override;
|
||||||
virtual bool tick() override;
|
virtual bool tick() override;
|
||||||
|
|
||||||
int readv(span<file::iovec_t const> bufs
|
int readv(span<iovec_t const> bufs
|
||||||
, piece_index_t piece, int offset, int flags, storage_error& ec) override;
|
, piece_index_t piece, int offset, int flags, storage_error& ec) override;
|
||||||
int writev(span<file::iovec_t const> bufs
|
int writev(span<iovec_t const> bufs
|
||||||
, piece_index_t piece, int offset, int flags, storage_error& ec) override;
|
, piece_index_t piece, int offset, int flags, storage_error& ec) override;
|
||||||
|
|
||||||
// if the files in this storage are mapped, returns the mapped
|
// if the files in this storage are mapped, returns the mapped
|
||||||
|
@ -563,24 +561,6 @@ namespace libtorrent
|
||||||
bool m_allocate_files;
|
bool m_allocate_files;
|
||||||
};
|
};
|
||||||
|
|
||||||
// this identifies a read or write operation so that readwritev() knows
|
|
||||||
// what to do when it's actually touching the file
|
|
||||||
struct fileop
|
|
||||||
{
|
|
||||||
virtual int file_op(file_index_t const file_index, std::int64_t const file_offset
|
|
||||||
, span<file::iovec_t const> bufs, storage_error& ec) = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
~fileop() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// this function is responsible for turning read and write operations in the
|
|
||||||
// torrent space (pieces) into read and write operations in the filesystem
|
|
||||||
// space (files on disk).
|
|
||||||
TORRENT_EXTRA_EXPORT int readwritev(file_storage const& files
|
|
||||||
, span<file::iovec_t const> bufs, piece_index_t piece, int offset
|
|
||||||
, fileop& op, storage_error& ec);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_STORAGE_HPP_INCLUDED
|
#endif // TORRENT_STORAGE_HPP_INCLUDED
|
||||||
|
|
|
@ -100,7 +100,7 @@ TORRENT_TEST(dht_bootstrap)
|
||||||
sim::default_config cfg;
|
sim::default_config cfg;
|
||||||
sim::simulation sim{cfg};
|
sim::simulation sim{cfg};
|
||||||
|
|
||||||
dht_network dht(sim, 2000);
|
dht_network dht(sim, 3000);
|
||||||
|
|
||||||
int routing_table_depth = 0;
|
int routing_table_depth = 0;
|
||||||
int num_nodes = 0;
|
int num_nodes = 0;
|
||||||
|
|
|
@ -124,11 +124,11 @@ void test_interval(int interval)
|
||||||
// make sure the interval is within 500 ms of what it's supposed to be
|
// make sure the interval is within 500 ms of what it's supposed to be
|
||||||
// (this accounts for network latencies)
|
// (this accounts for network latencies)
|
||||||
std::int64_t const actual_interval_ms = duration_cast<lt::milliseconds>(announces[i] - last_announce).count();
|
std::int64_t const actual_interval_ms = duration_cast<lt::milliseconds>(announces[i] - last_announce).count();
|
||||||
TEST_CHECK(abs(actual_interval_ms - interval * 1000) < 500);
|
TEST_CHECK(std::abs(actual_interval_ms - interval * 1000) < 500);
|
||||||
last_announce = announces[i];
|
last_announce = announces[i];
|
||||||
|
|
||||||
std::int64_t const alert_interval_ms = duration_cast<lt::milliseconds>(announce_alerts[i] - last_alert).count();
|
std::int64_t const alert_interval_ms = duration_cast<lt::milliseconds>(announce_alerts[i] - last_alert).count();
|
||||||
TEST_CHECK(abs(alert_interval_ms - interval * 1000) < 500);
|
TEST_CHECK(std::abs(alert_interval_ms - interval * 1000) < 500);
|
||||||
last_alert = announce_alerts[i];
|
last_alert = announce_alerts[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ TORRENT_TEST(event_completed)
|
||||||
{
|
{
|
||||||
// the announce should have come approximately the same time we
|
// the announce should have come approximately the same time we
|
||||||
// completed
|
// completed
|
||||||
TEST_CHECK(abs(completion - timestamp) <= 1);
|
TEST_CHECK(std::abs(completion - timestamp) <= 1);
|
||||||
TEST_CHECK(has_completed);
|
TEST_CHECK(has_completed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
||||||
stat.cpp \
|
stat.cpp \
|
||||||
stat_cache.cpp \
|
stat_cache.cpp \
|
||||||
storage.cpp \
|
storage.cpp \
|
||||||
|
storage_utils.cpp \
|
||||||
session_stats.cpp \
|
session_stats.cpp \
|
||||||
string_util.cpp \
|
string_util.cpp \
|
||||||
torrent.cpp \
|
torrent.cpp \
|
||||||
|
|
|
@ -1260,7 +1260,7 @@ int block_cache::pad_job(disk_io_job const* j, int blocks_in_piece
|
||||||
return end - start;
|
return end - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void block_cache::insert_blocks(cached_piece_entry* pe, int block, span<file::iovec_t const> iov
|
void block_cache::insert_blocks(cached_piece_entry* pe, int block, span<iovec_t const> iov
|
||||||
, disk_io_job* j, int const flags)
|
, disk_io_job* j, int const flags)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
||||||
|
|
|
@ -190,7 +190,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// this function allocates buffers and
|
// this function allocates buffers and
|
||||||
// fills in the iovec array with the buffers
|
// fills in the iovec array with the buffers
|
||||||
int disk_buffer_pool::allocate_iovec(span<file::iovec_t> iov)
|
int disk_buffer_pool::allocate_iovec(span<iovec_t> iov)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_pool_mutex);
|
std::unique_lock<std::mutex> l(m_pool_mutex);
|
||||||
for (auto& i : iov)
|
for (auto& i : iov)
|
||||||
|
@ -216,7 +216,7 @@ namespace libtorrent
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_buffer_pool::free_iovec(span<file::iovec_t const> iov)
|
void disk_buffer_pool::free_iovec(span<iovec_t const> iov)
|
||||||
{
|
{
|
||||||
// TODO: perhaps we should sort the buffers here?
|
// TODO: perhaps we should sort the buffers here?
|
||||||
std::unique_lock<std::mutex> l(m_pool_mutex);
|
std::unique_lock<std::mutex> l(m_pool_mutex);
|
||||||
|
|
|
@ -462,7 +462,7 @@ namespace libtorrent
|
||||||
|
|
||||||
cont_pieces = static_cast<int>(range_end) - static_cast<int>(range_start);
|
cont_pieces = static_cast<int>(range_end) - static_cast<int>(range_start);
|
||||||
int const blocks_to_flush = int(p->blocks_in_piece * cont_pieces);
|
int const blocks_to_flush = int(p->blocks_in_piece * cont_pieces);
|
||||||
TORRENT_ALLOCA(iov, file::iovec_t, blocks_to_flush);
|
TORRENT_ALLOCA(iov, iovec_t, blocks_to_flush);
|
||||||
TORRENT_ALLOCA(flushing, int, blocks_to_flush);
|
TORRENT_ALLOCA(flushing, int, blocks_to_flush);
|
||||||
// this is the offset into iov and flushing for each piece
|
// this is the offset into iov and flushing for each piece
|
||||||
TORRENT_ALLOCA(iovec_offset, int, cont_pieces + 1);
|
TORRENT_ALLOCA(iovec_offset, int, cont_pieces + 1);
|
||||||
|
@ -571,7 +571,7 @@ namespace libtorrent
|
||||||
// multiple pieces, the subsequent pieces after the first one, must have
|
// multiple pieces, the subsequent pieces after the first one, must have
|
||||||
// their block indices start where the previous one left off
|
// their block indices start where the previous one left off
|
||||||
int disk_io_thread::build_iovec(cached_piece_entry* pe, int start, int end
|
int disk_io_thread::build_iovec(cached_piece_entry* pe, int start, int end
|
||||||
, span<file::iovec_t> iov, span<int> flushing, int const block_base_index)
|
, span<iovec_t> iov, span<int> flushing, int const block_base_index)
|
||||||
{
|
{
|
||||||
DLOG("build_iovec: piece=%d [%d, %d)\n"
|
DLOG("build_iovec: piece=%d [%d, %d)\n"
|
||||||
, int(pe->piece), start, end);
|
, int(pe->piece), start, end);
|
||||||
|
@ -633,7 +633,7 @@ namespace libtorrent
|
||||||
// the cached_piece_entry is supposed to point to the
|
// the cached_piece_entry is supposed to point to the
|
||||||
// first piece, if the iovec spans multiple pieces
|
// first piece, if the iovec spans multiple pieces
|
||||||
void disk_io_thread::flush_iovec(cached_piece_entry* pe
|
void disk_io_thread::flush_iovec(cached_piece_entry* pe
|
||||||
, span<file::iovec_t const> iov, span<int const> flushing
|
, span<iovec_t const> iov, span<int const> flushing
|
||||||
, int const num_blocks, storage_error& error)
|
, int const num_blocks, storage_error& error)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_ASSERT(!error, pe);
|
TORRENT_PIECE_ASSERT(!error, pe);
|
||||||
|
@ -762,7 +762,7 @@ namespace libtorrent
|
||||||
TORRENT_PIECE_ASSERT(start >= 0, pe);
|
TORRENT_PIECE_ASSERT(start >= 0, pe);
|
||||||
TORRENT_PIECE_ASSERT(start < end, pe);
|
TORRENT_PIECE_ASSERT(start < end, pe);
|
||||||
|
|
||||||
TORRENT_ALLOCA(iov, file::iovec_t, std::size_t(pe->blocks_in_piece));
|
TORRENT_ALLOCA(iov, iovec_t, std::size_t(pe->blocks_in_piece));
|
||||||
TORRENT_ALLOCA(flushing, int, std::size_t(pe->blocks_in_piece));
|
TORRENT_ALLOCA(flushing, int, std::size_t(pe->blocks_in_piece));
|
||||||
int iov_len = build_iovec(pe, start, end, iov, flushing, 0);
|
int iov_len = build_iovec(pe, start, end, iov, flushing, 0);
|
||||||
if (iov_len == 0) return 0;
|
if (iov_len == 0) return 0;
|
||||||
|
@ -1217,7 +1217,7 @@ namespace libtorrent
|
||||||
|
|
||||||
int const file_flags = file_flags_for_job(j
|
int const file_flags = file_flags_for_job(j
|
||||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||||
file::iovec_t b = {j->buffer.disk_block, std::size_t(j->d.io.buffer_size)};
|
iovec_t b = {j->buffer.disk_block, std::size_t(j->d.io.buffer_size)};
|
||||||
|
|
||||||
int ret = j->storage->readv(b
|
int ret = j->storage->readv(b
|
||||||
, j->piece, j->d.io.offset, file_flags, j->error);
|
, j->piece, j->d.io.offset, file_flags, j->error);
|
||||||
|
@ -1247,7 +1247,7 @@ namespace libtorrent
|
||||||
int const iov_len = m_disk_cache.pad_job(j, blocks_in_piece
|
int const iov_len = m_disk_cache.pad_job(j, blocks_in_piece
|
||||||
, m_settings.get_int(settings_pack::read_cache_line_size));
|
, m_settings.get_int(settings_pack::read_cache_line_size));
|
||||||
|
|
||||||
TORRENT_ALLOCA(iov, file::iovec_t, iov_len);
|
TORRENT_ALLOCA(iov, iovec_t, iov_len);
|
||||||
|
|
||||||
std::unique_lock<std::mutex> l(m_cache_mutex);
|
std::unique_lock<std::mutex> l(m_cache_mutex);
|
||||||
|
|
||||||
|
@ -1449,7 +1449,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
time_point const start_time = clock_type::now();
|
time_point const start_time = clock_type::now();
|
||||||
|
|
||||||
file::iovec_t const b = {j->buffer.disk_block, std::size_t(j->d.io.buffer_size)};
|
iovec_t const b = {j->buffer.disk_block, std::size_t(j->d.io.buffer_size)};
|
||||||
int const file_flags = file_flags_for_job(j
|
int const file_flags = file_flags_for_job(j
|
||||||
, m_settings.get_bool(settings_pack::coalesce_writes));
|
, m_settings.get_bool(settings_pack::coalesce_writes));
|
||||||
|
|
||||||
|
@ -2141,7 +2141,7 @@ namespace libtorrent
|
||||||
int const file_flags = file_flags_for_job(j
|
int const file_flags = file_flags_for_job(j
|
||||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||||
|
|
||||||
file::iovec_t iov;
|
iovec_t iov;
|
||||||
iov.iov_base = m_disk_cache.allocate_buffer("hashing");
|
iov.iov_base = m_disk_cache.allocate_buffer("hashing");
|
||||||
hasher h;
|
hasher h;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -2305,7 +2305,7 @@ namespace libtorrent
|
||||||
int next_locked_block = 0;
|
int next_locked_block = 0;
|
||||||
for (int i = offset / block_size; i < blocks_in_piece; ++i)
|
for (int i = offset / block_size; i < blocks_in_piece; ++i)
|
||||||
{
|
{
|
||||||
file::iovec_t iov;
|
iovec_t iov;
|
||||||
iov.iov_len = (std::min)(block_size, piece_size - offset);
|
iov.iov_len = (std::min)(block_size, piece_size - offset);
|
||||||
|
|
||||||
if (next_locked_block < num_locked_blocks
|
if (next_locked_block < num_locked_blocks
|
||||||
|
|
26
src/file.cpp
26
src/file.cpp
|
@ -163,7 +163,7 @@ namespace
|
||||||
return WAIT_FAILED;
|
return WAIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int preadv(HANDLE fd, libtorrent::file::iovec_t const* bufs, int num_bufs, std::int64_t file_offset)
|
int preadv(HANDLE fd, libtorrent::iovec_t const* bufs, int num_bufs, std::int64_t file_offset)
|
||||||
{
|
{
|
||||||
TORRENT_ALLOCA(ol, OVERLAPPED, num_bufs);
|
TORRENT_ALLOCA(ol, OVERLAPPED, num_bufs);
|
||||||
std::memset(ol.data(), 0, sizeof(OVERLAPPED) * num_bufs);
|
std::memset(ol.data(), 0, sizeof(OVERLAPPED) * num_bufs);
|
||||||
|
@ -233,7 +233,7 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pwritev(HANDLE fd, libtorrent::file::iovec_t const* bufs, int num_bufs, std::int64_t file_offset)
|
int pwritev(HANDLE fd, libtorrent::iovec_t const* bufs, int num_bufs, std::int64_t file_offset)
|
||||||
{
|
{
|
||||||
TORRENT_ALLOCA(ol, OVERLAPPED, num_bufs);
|
TORRENT_ALLOCA(ol, OVERLAPPED, num_bufs);
|
||||||
std::memset(ol.data(), 0, sizeof(OVERLAPPED) * num_bufs);
|
std::memset(ol.data(), 0, sizeof(OVERLAPPED) * num_bufs);
|
||||||
|
@ -328,7 +328,7 @@ static_assert((libtorrent::file::sparse & libtorrent::file::attribute_mask) == 0
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
int bufs_size(span<file::iovec_t const> bufs)
|
int bufs_size(span<iovec_t const> bufs)
|
||||||
{
|
{
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
for (auto buf : bufs)
|
for (auto buf : bufs)
|
||||||
|
@ -1605,7 +1605,7 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#if !TORRENT_USE_PREADV
|
#if !TORRENT_USE_PREADV
|
||||||
void gather_copy(span<file::iovec_t const> bufs, char* dst)
|
void gather_copy(span<iovec_t const> bufs, char* dst)
|
||||||
{
|
{
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
for (auto buf : bufs)
|
for (auto buf : bufs)
|
||||||
|
@ -1615,7 +1615,7 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scatter_copy(span<file::iovec_t const> bufs, char const* src)
|
void scatter_copy(span<iovec_t const> bufs, char const* src)
|
||||||
{
|
{
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
for (auto buf : bufs)
|
for (auto buf : bufs)
|
||||||
|
@ -1625,27 +1625,27 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool coalesce_read_buffers(span<file::iovec_t const>& bufs
|
bool coalesce_read_buffers(span<iovec_t const>& bufs
|
||||||
, file::iovec_t& tmp)
|
, iovec_t& tmp)
|
||||||
{
|
{
|
||||||
int const buf_size = bufs_size(bufs);
|
int const buf_size = bufs_size(bufs);
|
||||||
char* buf = static_cast<char*>(std::malloc(buf_size));
|
char* buf = static_cast<char*>(std::malloc(buf_size));
|
||||||
if (!buf) return false;
|
if (!buf) return false;
|
||||||
tmp.iov_base = buf;
|
tmp.iov_base = buf;
|
||||||
tmp.iov_len = buf_size;
|
tmp.iov_len = buf_size;
|
||||||
bufs = span<file::iovec_t const>(tmp);
|
bufs = span<iovec_t const>(tmp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void coalesce_read_buffers_end(span<file::iovec_t const> bufs
|
void coalesce_read_buffers_end(span<iovec_t const> bufs
|
||||||
, char* const buf, bool const copy)
|
, char* const buf, bool const copy)
|
||||||
{
|
{
|
||||||
if (copy) scatter_copy(bufs, buf);
|
if (copy) scatter_copy(bufs, buf);
|
||||||
std::free(buf);
|
std::free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool coalesce_write_buffers(span<file::iovec_t const>& bufs
|
bool coalesce_write_buffers(span<iovec_t const>& bufs
|
||||||
, file::iovec_t& tmp)
|
, iovec_t& tmp)
|
||||||
{
|
{
|
||||||
int const buf_size = bufs_size(bufs);
|
int const buf_size = bufs_size(bufs);
|
||||||
char* buf = static_cast<char*>(std::malloc(buf_size));
|
char* buf = static_cast<char*>(std::malloc(buf_size));
|
||||||
|
@ -1653,14 +1653,14 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
||||||
gather_copy(bufs, buf);
|
gather_copy(bufs, buf);
|
||||||
tmp.iov_base = buf;
|
tmp.iov_base = buf;
|
||||||
tmp.iov_len = buf_size;
|
tmp.iov_len = buf_size;
|
||||||
bufs = span<file::iovec_t const>(tmp);
|
bufs = span<iovec_t const>(tmp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif // TORRENT_USE_PREADV
|
#endif // TORRENT_USE_PREADV
|
||||||
|
|
||||||
template <class Fun>
|
template <class Fun>
|
||||||
std::int64_t iov(Fun f, handle_type fd, std::int64_t file_offset
|
std::int64_t iov(Fun f, handle_type fd, std::int64_t file_offset
|
||||||
, span<file::iovec_t const> bufs, error_code& ec)
|
, span<iovec_t const> bufs, error_code& ec)
|
||||||
{
|
{
|
||||||
#if TORRENT_USE_PREADV
|
#if TORRENT_USE_PREADV
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
// parse header
|
// parse header
|
||||||
std::unique_ptr<std::uint32_t[]> header(new std::uint32_t[m_header_size]);
|
std::unique_ptr<std::uint32_t[]> header(new std::uint32_t[m_header_size]);
|
||||||
file::iovec_t b = {header.get(), std::size_t(m_header_size)};
|
iovec_t b = {header.get(), std::size_t(m_header_size)};
|
||||||
int n = int(m_file.readv(0, b, ec));
|
int n = int(m_file.readv(0, b, ec));
|
||||||
if (ec) return;
|
if (ec) return;
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ namespace libtorrent
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
int part_file::writev(span<file::iovec_t const> bufs, piece_index_t const piece
|
int part_file::writev(span<iovec_t const> bufs, piece_index_t const piece
|
||||||
, int offset, error_code& ec)
|
, int offset, error_code& ec)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(offset >= 0);
|
TORRENT_ASSERT(offset >= 0);
|
||||||
|
@ -190,7 +190,7 @@ namespace libtorrent
|
||||||
return int(m_file.writev(slot_offset + offset, bufs, ec));
|
return int(m_file.writev(slot_offset + offset, bufs, ec));
|
||||||
}
|
}
|
||||||
|
|
||||||
int part_file::readv(span<file::iovec_t const> bufs
|
int part_file::readv(span<iovec_t const> bufs
|
||||||
, piece_index_t const piece, int offset, error_code& ec)
|
, piece_index_t const piece, int offset, error_code& ec)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(offset >= 0);
|
TORRENT_ASSERT(offset >= 0);
|
||||||
|
@ -324,7 +324,7 @@ namespace libtorrent
|
||||||
// don't hold the lock during disk I/O
|
// don't hold the lock during disk I/O
|
||||||
l.unlock();
|
l.unlock();
|
||||||
|
|
||||||
file::iovec_t v = {buf.get(), std::size_t(block_to_copy)};
|
iovec_t v = {buf.get(), std::size_t(block_to_copy)};
|
||||||
v.iov_len = std::size_t(m_file.readv(slot_offset + piece_offset, v, ec));
|
v.iov_len = std::size_t(m_file.readv(slot_offset + piece_offset, v, ec));
|
||||||
TORRENT_ASSERT(!ec);
|
TORRENT_ASSERT(!ec);
|
||||||
if (ec || v.iov_len == 0) return;
|
if (ec || v.iov_len == 0) return;
|
||||||
|
@ -409,7 +409,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
std::memset(ptr, 0, m_header_size - (ptr - reinterpret_cast<char*>(header.get())));
|
std::memset(ptr, 0, m_header_size - (ptr - reinterpret_cast<char*>(header.get())));
|
||||||
|
|
||||||
file::iovec_t b = {header.get(), std::size_t(m_header_size)};
|
iovec_t b = {header.get(), std::size_t(m_header_size)};
|
||||||
m_file.writev(0, b, ec);
|
m_file.writev(0, b, ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
166
src/storage.cpp
166
src/storage.cpp
|
@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
|
#include "libtorrent/aux_/storage_utils.hpp"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -70,7 +71,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/file_pool.hpp"
|
#include "libtorrent/file_pool.hpp"
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
#include "libtorrent/disk_buffer_holder.hpp"
|
#include "libtorrent/disk_buffer_holder.hpp"
|
||||||
#include "libtorrent/alloca.hpp"
|
|
||||||
#include "libtorrent/stat_cache.hpp"
|
#include "libtorrent/stat_cache.hpp"
|
||||||
#include "libtorrent/hex.hpp" // to_hex
|
#include "libtorrent/hex.hpp" // to_hex
|
||||||
// for convert_to_wstring and convert_to_native
|
// for convert_to_wstring and convert_to_native
|
||||||
|
@ -113,62 +113,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
int copy_bufs(span<file::iovec_t const> bufs, int bytes, span<file::iovec_t> target)
|
void clear_bufs(span<iovec_t const> bufs)
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
for (int i = 0;; i++)
|
|
||||||
{
|
|
||||||
target[i] = bufs[i];
|
|
||||||
size += int(bufs[i].iov_len);
|
|
||||||
if (size >= bytes)
|
|
||||||
{
|
|
||||||
target[i].iov_len -= size - bytes;
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span<file::iovec_t> advance_bufs(span<file::iovec_t> bufs, int bytes)
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
size += int(bufs.front().iov_len);
|
|
||||||
if (size >= bytes)
|
|
||||||
{
|
|
||||||
bufs.front().iov_base = reinterpret_cast<char*>(bufs.front().iov_base)
|
|
||||||
+ bufs.front().iov_len - (size - bytes);
|
|
||||||
bufs.front().iov_len = size - bytes;
|
|
||||||
return bufs;
|
|
||||||
}
|
|
||||||
bufs = bufs.subspan(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_bufs(span<file::iovec_t const> bufs)
|
|
||||||
{
|
{
|
||||||
for (auto buf : bufs)
|
for (auto buf : bufs)
|
||||||
std::memset(buf.iov_base, 0, buf.iov_len);
|
std::memset(buf.iov_base, 0, buf.iov_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
|
||||||
int count_bufs(span<file::iovec_t const> bufs, int bytes)
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
int count = 1;
|
|
||||||
if (bytes == 0) return 0;
|
|
||||||
for (auto i = bufs.begin();; ++i, ++count)
|
|
||||||
{
|
|
||||||
size += int(i->iov_len);
|
|
||||||
if (size >= bytes) return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
struct write_fileop final : fileop
|
struct write_fileop final : fileop
|
||||||
{
|
{
|
||||||
write_fileop(default_storage& st, int flags)
|
write_fileop(default_storage& st, int flags)
|
||||||
|
@ -178,7 +128,7 @@ namespace libtorrent
|
||||||
|
|
||||||
int file_op(file_index_t const file_index
|
int file_op(file_index_t const file_index
|
||||||
, std::int64_t const file_offset
|
, std::int64_t const file_offset
|
||||||
, span<file::iovec_t const> bufs, storage_error& ec)
|
, span<iovec_t const> bufs, storage_error& ec)
|
||||||
final
|
final
|
||||||
{
|
{
|
||||||
if (m_storage.files().pad_file_at(file_index))
|
if (m_storage.files().pad_file_at(file_index))
|
||||||
|
@ -258,7 +208,7 @@ namespace libtorrent
|
||||||
|
|
||||||
int file_op(file_index_t const file_index
|
int file_op(file_index_t const file_index
|
||||||
, std::int64_t const file_offset
|
, std::int64_t const file_offset
|
||||||
, span<file::iovec_t const> bufs, storage_error& ec)
|
, span<iovec_t const> bufs, storage_error& ec)
|
||||||
final
|
final
|
||||||
{
|
{
|
||||||
if (m_storage.files().pad_file_at(file_index))
|
if (m_storage.files().pad_file_at(file_index))
|
||||||
|
@ -1036,7 +986,7 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int default_storage::readv(span<file::iovec_t const> bufs
|
int default_storage::readv(span<iovec_t const> bufs
|
||||||
, piece_index_t const piece, int offset, int flags, storage_error& ec)
|
, piece_index_t const piece, int offset, int flags, storage_error& ec)
|
||||||
{
|
{
|
||||||
read_fileop op(*this, flags);
|
read_fileop op(*this, flags);
|
||||||
|
@ -1047,109 +997,13 @@ namespace libtorrent
|
||||||
return readwritev(files(), bufs, piece, offset, op, ec);
|
return readwritev(files(), bufs, piece, offset, op, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
int default_storage::writev(span<file::iovec_t const> bufs
|
int default_storage::writev(span<iovec_t const> bufs
|
||||||
, piece_index_t const piece, int offset, int flags, storage_error& ec)
|
, piece_index_t const piece, int offset, int flags, storage_error& ec)
|
||||||
{
|
{
|
||||||
write_fileop op(*this, flags);
|
write_fileop op(*this, flags);
|
||||||
return readwritev(files(), bufs, piece, offset, op, ec);
|
return readwritev(files(), bufs, piece, offset, op, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// much of what needs to be done when reading and writing is buffer
|
|
||||||
// management and piece to file mapping. Most of that is the same for reading
|
|
||||||
// and writing. This function is a template, and the fileop decides what to
|
|
||||||
// do with the file and the buffers.
|
|
||||||
int readwritev(file_storage const& files, span<file::iovec_t const> const bufs
|
|
||||||
, piece_index_t const piece, const int offset, fileop& op
|
|
||||||
, storage_error& ec)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(piece >= piece_index_t(0));
|
|
||||||
TORRENT_ASSERT(piece < files.end_piece());
|
|
||||||
TORRENT_ASSERT(offset >= 0);
|
|
||||||
TORRENT_ASSERT(bufs.size() > 0);
|
|
||||||
|
|
||||||
const int size = bufs_size(bufs);
|
|
||||||
TORRENT_ASSERT(size > 0);
|
|
||||||
|
|
||||||
// find the file iterator and file offset
|
|
||||||
std::int64_t const torrent_offset = static_cast<int>(piece) * std::int64_t(files.piece_length()) + offset;
|
|
||||||
file_index_t file_index = files.file_index_at_offset(torrent_offset);
|
|
||||||
TORRENT_ASSERT(torrent_offset >= files.file_offset(file_index));
|
|
||||||
TORRENT_ASSERT(torrent_offset < files.file_offset(file_index) + files.file_size(file_index));
|
|
||||||
std::int64_t file_offset = torrent_offset - files.file_offset(file_index);
|
|
||||||
|
|
||||||
// the number of bytes left before this read or write operation is
|
|
||||||
// completely satisfied.
|
|
||||||
int bytes_left = size;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(bytes_left >= 0);
|
|
||||||
|
|
||||||
// copy the iovec array so we can use it to keep track of our current
|
|
||||||
// location by updating the head base pointer and size. (see
|
|
||||||
// advance_bufs())
|
|
||||||
TORRENT_ALLOCA(current_buf, file::iovec_t, bufs.size());
|
|
||||||
copy_bufs(bufs, size, current_buf);
|
|
||||||
TORRENT_ASSERT(count_bufs(current_buf, size) == int(bufs.size()));
|
|
||||||
|
|
||||||
TORRENT_ALLOCA(tmp_buf, file::iovec_t, bufs.size());
|
|
||||||
|
|
||||||
// the number of bytes left to read in the current file (specified by
|
|
||||||
// file_index). This is the minimum of (file_size - file_offset) and
|
|
||||||
// bytes_left.
|
|
||||||
int file_bytes_left;
|
|
||||||
|
|
||||||
while (bytes_left > 0)
|
|
||||||
{
|
|
||||||
file_bytes_left = bytes_left;
|
|
||||||
if (file_offset + file_bytes_left > files.file_size(file_index))
|
|
||||||
file_bytes_left = (std::max)(static_cast<int>(files.file_size(file_index) - file_offset), 0);
|
|
||||||
|
|
||||||
// there are no bytes left in this file, move to the next one
|
|
||||||
// this loop skips over empty files
|
|
||||||
while (file_bytes_left == 0)
|
|
||||||
{
|
|
||||||
++file_index;
|
|
||||||
file_offset = 0;
|
|
||||||
TORRENT_ASSERT(file_index < files.end_file());
|
|
||||||
|
|
||||||
// this should not happen. bytes_left should be clamped by the total
|
|
||||||
// size of the torrent, so we should never run off the end of it
|
|
||||||
if (file_index >= files.end_file()) return size;
|
|
||||||
|
|
||||||
file_bytes_left = bytes_left;
|
|
||||||
if (file_offset + file_bytes_left > files.file_size(file_index))
|
|
||||||
file_bytes_left = (std::max)(static_cast<int>(files.file_size(file_index) - file_offset), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make a copy of the iovec array that _just_ covers the next
|
|
||||||
// file_bytes_left bytes, i.e. just this one operation
|
|
||||||
int tmp_bufs_used = copy_bufs(current_buf, file_bytes_left, tmp_buf);
|
|
||||||
|
|
||||||
int bytes_transferred = op.file_op(file_index, file_offset
|
|
||||||
, tmp_buf.first(tmp_bufs_used), ec);
|
|
||||||
if (ec) return -1;
|
|
||||||
|
|
||||||
// advance our position in the iovec array and the file offset.
|
|
||||||
current_buf = advance_bufs(current_buf, bytes_transferred);
|
|
||||||
bytes_left -= bytes_transferred;
|
|
||||||
file_offset += bytes_transferred;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(count_bufs(current_buf, bytes_left) <= int(bufs.size()));
|
|
||||||
|
|
||||||
// if the file operation returned 0, we've hit end-of-file. We're done
|
|
||||||
if (bytes_transferred == 0)
|
|
||||||
{
|
|
||||||
if (file_bytes_left > 0 )
|
|
||||||
{
|
|
||||||
// fill in this information in case the caller wants to treat
|
|
||||||
// a short-read as an error
|
|
||||||
ec.file(file_index);
|
|
||||||
}
|
|
||||||
return size - bytes_left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_handle default_storage::open_file(file_index_t const file, int mode
|
file_handle default_storage::open_file(file_index_t const file, int mode
|
||||||
, storage_error& ec) const
|
, storage_error& ec) const
|
||||||
{
|
{
|
||||||
|
@ -1285,12 +1139,12 @@ namespace libtorrent
|
||||||
void initialize(storage_error&) override {}
|
void initialize(storage_error&) override {}
|
||||||
status_t move_storage(std::string const&, int, storage_error&) override { return status_t::no_error; }
|
status_t move_storage(std::string const&, int, storage_error&) override { return status_t::no_error; }
|
||||||
|
|
||||||
int readv(span<file::iovec_t const> bufs
|
int readv(span<iovec_t const> bufs
|
||||||
, piece_index_t, int, int, storage_error&) override
|
, piece_index_t, int, int, storage_error&) override
|
||||||
{
|
{
|
||||||
return bufs_size(bufs);
|
return bufs_size(bufs);
|
||||||
}
|
}
|
||||||
int writev(span<file::iovec_t const> bufs
|
int writev(span<iovec_t const> bufs
|
||||||
, piece_index_t, int, int, storage_error&) override
|
, piece_index_t, int, int, storage_error&) override
|
||||||
{
|
{
|
||||||
return bufs_size(bufs);
|
return bufs_size(bufs);
|
||||||
|
@ -1318,7 +1172,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
void initialize(storage_error&) override {}
|
void initialize(storage_error&) override {}
|
||||||
|
|
||||||
int readv(span<file::iovec_t const> bufs
|
int readv(span<iovec_t const> bufs
|
||||||
, piece_index_t, int, int, storage_error&) override
|
, piece_index_t, int, int, storage_error&) override
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1329,7 +1183,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int writev(span<file::iovec_t const> bufs
|
int writev(span<iovec_t const> bufs
|
||||||
, piece_index_t, int, int, storage_error&) override
|
, piece_index_t, int, int, storage_error&) override
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2003-2016, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libtorrent/aux_/storage_utils.hpp"
|
||||||
|
#include "libtorrent/file_storage.hpp"
|
||||||
|
#include "libtorrent/alloca.hpp"
|
||||||
|
#include "libtorrent/file.hpp" // for count_bufs
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
int copy_bufs(span<iovec_t const> bufs, int bytes, span<iovec_t> target)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
for (int i = 0;; i++)
|
||||||
|
{
|
||||||
|
target[i] = bufs[i];
|
||||||
|
size += int(bufs[i].iov_len);
|
||||||
|
if (size >= bytes)
|
||||||
|
{
|
||||||
|
target[i].iov_len -= size - bytes;
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span<iovec_t> advance_bufs(span<iovec_t> bufs, int bytes)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
size += int(bufs.front().iov_len);
|
||||||
|
if (size >= bytes)
|
||||||
|
{
|
||||||
|
bufs.front().iov_base = reinterpret_cast<char*>(bufs.front().iov_base)
|
||||||
|
+ bufs.front().iov_len - (size - bytes);
|
||||||
|
bufs.front().iov_len = size - bytes;
|
||||||
|
return bufs;
|
||||||
|
}
|
||||||
|
bufs = bufs.subspan(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TORRENT_USE_ASSERTS
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int count_bufs(span<iovec_t const> bufs, int bytes)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
int count = 1;
|
||||||
|
if (bytes == 0) return 0;
|
||||||
|
for (auto i = bufs.begin();; ++i, ++count)
|
||||||
|
{
|
||||||
|
size += int(i->iov_len);
|
||||||
|
if (size >= bytes) return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// much of what needs to be done when reading and writing is buffer
|
||||||
|
// management and piece to file mapping. Most of that is the same for reading
|
||||||
|
// and writing. This function is a template, and the fileop decides what to
|
||||||
|
// do with the file and the buffers.
|
||||||
|
int readwritev(file_storage const& files, span<iovec_t const> const bufs
|
||||||
|
, piece_index_t const piece, const int offset, fileop& op
|
||||||
|
, storage_error& ec)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(piece >= piece_index_t(0));
|
||||||
|
TORRENT_ASSERT(piece < files.end_piece());
|
||||||
|
TORRENT_ASSERT(offset >= 0);
|
||||||
|
TORRENT_ASSERT(bufs.size() > 0);
|
||||||
|
|
||||||
|
const int size = bufs_size(bufs);
|
||||||
|
TORRENT_ASSERT(size > 0);
|
||||||
|
|
||||||
|
// find the file iterator and file offset
|
||||||
|
std::int64_t const torrent_offset = static_cast<int>(piece) * std::int64_t(files.piece_length()) + offset;
|
||||||
|
file_index_t file_index = files.file_index_at_offset(torrent_offset);
|
||||||
|
TORRENT_ASSERT(torrent_offset >= files.file_offset(file_index));
|
||||||
|
TORRENT_ASSERT(torrent_offset < files.file_offset(file_index) + files.file_size(file_index));
|
||||||
|
std::int64_t file_offset = torrent_offset - files.file_offset(file_index);
|
||||||
|
|
||||||
|
// the number of bytes left before this read or write operation is
|
||||||
|
// completely satisfied.
|
||||||
|
int bytes_left = size;
|
||||||
|
|
||||||
|
TORRENT_ASSERT(bytes_left >= 0);
|
||||||
|
|
||||||
|
// copy the iovec array so we can use it to keep track of our current
|
||||||
|
// location by updating the head base pointer and size. (see
|
||||||
|
// advance_bufs())
|
||||||
|
TORRENT_ALLOCA(current_buf, iovec_t, bufs.size());
|
||||||
|
copy_bufs(bufs, size, current_buf);
|
||||||
|
TORRENT_ASSERT(count_bufs(current_buf, size) == int(bufs.size()));
|
||||||
|
|
||||||
|
TORRENT_ALLOCA(tmp_buf, iovec_t, bufs.size());
|
||||||
|
|
||||||
|
// the number of bytes left to read in the current file (specified by
|
||||||
|
// file_index). This is the minimum of (file_size - file_offset) and
|
||||||
|
// bytes_left.
|
||||||
|
int file_bytes_left;
|
||||||
|
|
||||||
|
while (bytes_left > 0)
|
||||||
|
{
|
||||||
|
file_bytes_left = bytes_left;
|
||||||
|
if (file_offset + file_bytes_left > files.file_size(file_index))
|
||||||
|
file_bytes_left = (std::max)(static_cast<int>(files.file_size(file_index) - file_offset), 0);
|
||||||
|
|
||||||
|
// there are no bytes left in this file, move to the next one
|
||||||
|
// this loop skips over empty files
|
||||||
|
while (file_bytes_left == 0)
|
||||||
|
{
|
||||||
|
++file_index;
|
||||||
|
file_offset = 0;
|
||||||
|
TORRENT_ASSERT(file_index < files.end_file());
|
||||||
|
|
||||||
|
// this should not happen. bytes_left should be clamped by the total
|
||||||
|
// size of the torrent, so we should never run off the end of it
|
||||||
|
if (file_index >= files.end_file()) return size;
|
||||||
|
|
||||||
|
file_bytes_left = bytes_left;
|
||||||
|
if (file_offset + file_bytes_left > files.file_size(file_index))
|
||||||
|
file_bytes_left = (std::max)(static_cast<int>(files.file_size(file_index) - file_offset), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make a copy of the iovec array that _just_ covers the next
|
||||||
|
// file_bytes_left bytes, i.e. just this one operation
|
||||||
|
int tmp_bufs_used = copy_bufs(current_buf, file_bytes_left, tmp_buf);
|
||||||
|
|
||||||
|
int bytes_transferred = op.file_op(file_index, file_offset
|
||||||
|
, tmp_buf.first(tmp_bufs_used), ec);
|
||||||
|
if (ec) return -1;
|
||||||
|
|
||||||
|
// advance our position in the iovec array and the file offset.
|
||||||
|
current_buf = advance_bufs(current_buf, bytes_transferred);
|
||||||
|
bytes_left -= bytes_transferred;
|
||||||
|
file_offset += bytes_transferred;
|
||||||
|
|
||||||
|
TORRENT_ASSERT(count_bufs(current_buf, bytes_left) <= int(bufs.size()));
|
||||||
|
|
||||||
|
// if the file operation returned 0, we've hit end-of-file. We're done
|
||||||
|
if (bytes_transferred == 0)
|
||||||
|
{
|
||||||
|
if (file_bytes_left > 0 )
|
||||||
|
{
|
||||||
|
// fill in this information in case the caller wants to treat
|
||||||
|
// a short-read as an error
|
||||||
|
ec.file(file_index);
|
||||||
|
}
|
||||||
|
return size - bytes_left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -616,7 +616,7 @@ namespace libtorrent
|
||||||
if (ec) return -1;
|
if (ec) return -1;
|
||||||
v.resize(std::size_t(s));
|
v.resize(std::size_t(s));
|
||||||
if (s == 0) return 0;
|
if (s == 0) return 0;
|
||||||
file::iovec_t b = {&v[0], size_t(s) };
|
iovec_t b = {&v[0], size_t(s) };
|
||||||
std::int64_t read = f.readv(0, b, ec);
|
std::int64_t read = f.readv(0, b, ec);
|
||||||
if (read != s) return -3;
|
if (read != s) return -3;
|
||||||
if (ec) return -3;
|
if (ec) return -3;
|
||||||
|
|
|
@ -190,7 +190,7 @@ void generate_files(libtorrent::torrent_info const& ti, std::string const& path
|
||||||
memcpy(&buffer[o], &data, 1);
|
memcpy(&buffer[o], &data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
file::iovec_t b = { &buffer[0], size_t(piece_size) };
|
iovec_t b = { &buffer[0], size_t(piece_size) };
|
||||||
storage_error ec;
|
storage_error ec;
|
||||||
int ret = st.writev(b, i, 0, 0, ec);
|
int ret = st.writev(b, i, 0, 0, ec);
|
||||||
if (ret != piece_size || ec)
|
if (ret != piece_size || ec)
|
||||||
|
|
|
@ -278,7 +278,7 @@ void save_file(char const* filename, char const* data, int size)
|
||||||
std::printf("ERROR opening file '%s': %s\n", filename, ec.message().c_str());
|
std::printf("ERROR opening file '%s': %s\n", filename, ec.message().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file::iovec_t b = { (void*)data, size_t(size) };
|
iovec_t b = { (void*)data, size_t(size) };
|
||||||
out.writev(0, b, ec);
|
out.writev(0, b, ec);
|
||||||
TEST_CHECK(!ec);
|
TEST_CHECK(!ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
|
@ -693,7 +693,7 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu
|
||||||
while (to_write > 0)
|
while (to_write > 0)
|
||||||
{
|
{
|
||||||
int s = (std::min)(to_write, 300000);
|
int s = (std::min)(to_write, 300000);
|
||||||
file::iovec_t b = { random_data, size_t(s)};
|
iovec_t b = { random_data, size_t(s)};
|
||||||
f.writev(offset, b, ec);
|
f.writev(offset, b, ec);
|
||||||
if (ec) std::printf("failed to write file \"%s\": (%d) %s\n"
|
if (ec) std::printf("failed to write file \"%s\": (%d) %s\n"
|
||||||
, full_path.c_str(), ec.value(), ec.message().c_str());
|
, full_path.c_str(), ec.value(), ec.message().c_str());
|
||||||
|
|
|
@ -48,12 +48,12 @@ struct test_storage_impl : storage_interface
|
||||||
{
|
{
|
||||||
void initialize(storage_error& ec) override {}
|
void initialize(storage_error& ec) override {}
|
||||||
|
|
||||||
int readv(span<file::iovec_t const> bufs
|
int readv(span<iovec_t const> bufs
|
||||||
, piece_index_t piece, int offset, int flags, storage_error& ec) override
|
, piece_index_t piece, int offset, int flags, storage_error& ec) override
|
||||||
{
|
{
|
||||||
return bufs_size(bufs);
|
return bufs_size(bufs);
|
||||||
}
|
}
|
||||||
int writev(span<file::iovec_t const> bufs
|
int writev(span<iovec_t const> bufs
|
||||||
, piece_index_t piece, int offset, int flags, storage_error& ec) override
|
, piece_index_t piece, int offset, int flags, storage_error& ec) override
|
||||||
{
|
{
|
||||||
return bufs_size(bufs);
|
return bufs_size(bufs);
|
||||||
|
@ -109,7 +109,7 @@ static void nop() {}
|
||||||
wj.storage = pm; \
|
wj.storage = pm; \
|
||||||
cached_piece_entry* pe = nullptr; \
|
cached_piece_entry* pe = nullptr; \
|
||||||
int ret = 0; \
|
int ret = 0; \
|
||||||
file::iovec_t iov; \
|
iovec_t iov; \
|
||||||
(void)iov; \
|
(void)iov; \
|
||||||
(void)ret; \
|
(void)ret; \
|
||||||
(void)pe
|
(void)pe
|
||||||
|
|
|
@ -54,7 +54,7 @@ int touch_file(std::string const& filename, int size)
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if (!f.open(filename, file::write_only, ec)) return -1;
|
if (!f.open(filename, file::write_only, ec)) return -1;
|
||||||
if (ec) return -1;
|
if (ec) return -1;
|
||||||
file::iovec_t b = {&v[0], v.size()};
|
iovec_t b = {&v[0], v.size()};
|
||||||
std::int64_t written = f.writev(0, b, ec);
|
std::int64_t written = f.writev(0, b, ec);
|
||||||
if (written != int(v.size())) return -3;
|
if (written != int(v.size())) return -3;
|
||||||
if (ec) return -3;
|
if (ec) return -3;
|
||||||
|
@ -300,7 +300,7 @@ TORRENT_TEST(file)
|
||||||
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||||
TEST_EQUAL(ec, error_code());
|
TEST_EQUAL(ec, error_code());
|
||||||
if (ec) std::printf("%s\n", ec.message().c_str());
|
if (ec) std::printf("%s\n", ec.message().c_str());
|
||||||
file::iovec_t b = {(void*)"test", 4};
|
iovec_t b = {(void*)"test", 4};
|
||||||
TEST_EQUAL(f.writev(0, b, ec), 4);
|
TEST_EQUAL(f.writev(0, b, ec), 4);
|
||||||
if (ec)
|
if (ec)
|
||||||
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||||
|
@ -330,7 +330,7 @@ TORRENT_TEST(hard_link)
|
||||||
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||||
TEST_EQUAL(ec, error_code());
|
TEST_EQUAL(ec, error_code());
|
||||||
|
|
||||||
file::iovec_t b = {(void*)"abcdefghijklmnopqrstuvwxyz", 26};
|
iovec_t b = {(void*)"abcdefghijklmnopqrstuvwxyz", 26};
|
||||||
TEST_EQUAL(f.writev(0, b, ec), 26);
|
TEST_EQUAL(f.writev(0, b, ec), 26);
|
||||||
if (ec)
|
if (ec)
|
||||||
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||||
|
@ -377,7 +377,7 @@ TORRENT_TEST(coalesce_buffer)
|
||||||
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||||
TEST_EQUAL(ec, error_code());
|
TEST_EQUAL(ec, error_code());
|
||||||
if (ec) std::printf("%s\n", ec.message().c_str());
|
if (ec) std::printf("%s\n", ec.message().c_str());
|
||||||
file::iovec_t b[2] = {{(void*)"test", 4}, {(void*)"foobar", 6}};
|
iovec_t b[2] = {{(void*)"test", 4}, {(void*)"foobar", 6}};
|
||||||
TEST_EQUAL(f.writev(0, {b, 2}, ec, file::coalesce_buffers), 4 + 6);
|
TEST_EQUAL(f.writev(0, {b, 2}, ec, file::coalesce_buffers), 4 + 6);
|
||||||
if (ec)
|
if (ec)
|
||||||
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
std::printf("writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||||
|
|
|
@ -151,7 +151,7 @@ void write_test_file()
|
||||||
file test_file("test_file", file::write_only, ec);
|
file test_file("test_file", file::write_only, ec);
|
||||||
TEST_CHECK(!ec);
|
TEST_CHECK(!ec);
|
||||||
if (ec) std::printf("file error: %s\n", ec.message().c_str());
|
if (ec) std::printf("file error: %s\n", ec.message().c_str());
|
||||||
file::iovec_t b = { data_buffer, 3216};
|
iovec_t b = { data_buffer, 3216};
|
||||||
test_file.writev(0, b, ec);
|
test_file.writev(0, b, ec);
|
||||||
TEST_CHECK(!ec);
|
TEST_CHECK(!ec);
|
||||||
if (ec) std::printf("file error: %s\n", ec.message().c_str());
|
if (ec) std::printf("file error: %s\n", ec.message().c_str());
|
||||||
|
|
|
@ -69,7 +69,7 @@ TORRENT_TEST(part_file)
|
||||||
// write something to the metadata file
|
// write something to the metadata file
|
||||||
for (int i = 0; i < 1024; ++i) buf[i] = i;
|
for (int i = 0; i < 1024; ++i) buf[i] = i;
|
||||||
|
|
||||||
file::iovec_t v = {&buf, 1024};
|
iovec_t v = {&buf, 1024};
|
||||||
pf.writev(v, piece_index_t(10), 0, ec);
|
pf.writev(v, piece_index_t(10), 0, ec);
|
||||||
if (ec) std::printf("part_file::writev: %s\n", ec.message().c_str());
|
if (ec) std::printf("part_file::writev: %s\n", ec.message().c_str());
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ TORRENT_TEST(part_file)
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
file::iovec_t v = {&buf, 1024};
|
iovec_t v = {&buf, 1024};
|
||||||
pf.readv(v, piece_index_t(10), 0, ec);
|
pf.readv(v, piece_index_t(10), 0, ec);
|
||||||
if (ec) std::printf("part_file::readv: %s\n", ec.message().c_str());
|
if (ec) std::printf("part_file::readv: %s\n", ec.message().c_str());
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,7 @@ void run_storage_tests(std::shared_ptr<torrent_info> info
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
// write piece 1 (in slot 0)
|
// write piece 1 (in slot 0)
|
||||||
file::iovec_t iov = { piece1.data(), half};
|
iovec_t iov = { piece1.data(), half};
|
||||||
ret = s->writev(iov, piece_index_t(0), 0, 0, ec);
|
ret = s->writev(iov, piece_index_t(0), 0, 0, ec);
|
||||||
if (ret != half) print_error("writev", ret, ec);
|
if (ret != half) print_error("writev", ret, ec);
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ void test_remove(std::string const& test_path, bool unbuffered)
|
||||||
TEST_CHECK(!exists(combine_path(test_path, combine_path("temp_storage"
|
TEST_CHECK(!exists(combine_path(test_path, combine_path("temp_storage"
|
||||||
, combine_path("folder1", "test2.tmp")))));
|
, combine_path("folder1", "test2.tmp")))));
|
||||||
|
|
||||||
file::iovec_t b = {&buf[0], 4};
|
iovec_t b = {&buf[0], 4};
|
||||||
storage_error se;
|
storage_error se;
|
||||||
s->writev(b, piece_index_t(2), 0, 0, se);
|
s->writev(b, piece_index_t(2), 0, 0, se);
|
||||||
|
|
||||||
|
@ -930,7 +930,7 @@ TORRENT_TEST(rename_file_fastresume_deprecated)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void alloc_iov(file::iovec_t* iov, int num_bufs)
|
void alloc_iov(iovec_t* iov, int num_bufs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num_bufs; ++i)
|
for (int i = 0; i < num_bufs; ++i)
|
||||||
{
|
{
|
||||||
|
@ -939,7 +939,7 @@ void alloc_iov(file::iovec_t* iov, int num_bufs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_pattern(file::iovec_t* iov, int num_bufs)
|
void fill_pattern(iovec_t* iov, int num_bufs)
|
||||||
{
|
{
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
for (int i = 0; i < num_bufs; ++i)
|
for (int i = 0; i < num_bufs; ++i)
|
||||||
|
@ -964,7 +964,7 @@ bool check_pattern(std::vector<char> const& buf, int counter)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_pattern2(file::iovec_t* iov, int num_bufs)
|
void fill_pattern2(iovec_t* iov, int num_bufs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num_bufs; ++i)
|
for (int i = 0; i < num_bufs; ++i)
|
||||||
{
|
{
|
||||||
|
@ -973,7 +973,7 @@ void fill_pattern2(file::iovec_t* iov, int num_bufs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_iov(file::iovec_t* iov, int num_bufs)
|
void free_iov(iovec_t* iov, int num_bufs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num_bufs; ++i)
|
for (int i = 0; i < num_bufs; ++i)
|
||||||
{
|
{
|
||||||
|
@ -985,8 +985,8 @@ void free_iov(file::iovec_t* iov, int num_bufs)
|
||||||
|
|
||||||
TORRENT_TEST(iovec_copy_bufs)
|
TORRENT_TEST(iovec_copy_bufs)
|
||||||
{
|
{
|
||||||
file::iovec_t iov1[10];
|
iovec_t iov1[10];
|
||||||
file::iovec_t iov2[10];
|
iovec_t iov2[10];
|
||||||
|
|
||||||
alloc_iov(iov1, 10);
|
alloc_iov(iov1, 10);
|
||||||
fill_pattern(iov1, 10);
|
fill_pattern(iov1, 10);
|
||||||
|
@ -1016,7 +1016,7 @@ TORRENT_TEST(iovec_copy_bufs)
|
||||||
|
|
||||||
TORRENT_TEST(iovec_clear_bufs)
|
TORRENT_TEST(iovec_clear_bufs)
|
||||||
{
|
{
|
||||||
file::iovec_t iov[10];
|
iovec_t iov[10];
|
||||||
alloc_iov(iov, 10);
|
alloc_iov(iov, 10);
|
||||||
fill_pattern(iov, 10);
|
fill_pattern(iov, 10);
|
||||||
|
|
||||||
|
@ -1034,7 +1034,7 @@ TORRENT_TEST(iovec_clear_bufs)
|
||||||
|
|
||||||
TORRENT_TEST(iovec_bufs_size)
|
TORRENT_TEST(iovec_bufs_size)
|
||||||
{
|
{
|
||||||
file::iovec_t iov[10];
|
iovec_t iov[10];
|
||||||
|
|
||||||
for (int i = 1; i < 10; ++i)
|
for (int i = 1; i < 10; ++i)
|
||||||
{
|
{
|
||||||
|
@ -1050,14 +1050,14 @@ TORRENT_TEST(iovec_bufs_size)
|
||||||
|
|
||||||
TORRENT_TEST(iovec_advance_bufs)
|
TORRENT_TEST(iovec_advance_bufs)
|
||||||
{
|
{
|
||||||
file::iovec_t iov1[10];
|
iovec_t iov1[10];
|
||||||
file::iovec_t iov2[10];
|
iovec_t iov2[10];
|
||||||
alloc_iov(iov1, 10);
|
alloc_iov(iov1, 10);
|
||||||
fill_pattern(iov1, 10);
|
fill_pattern(iov1, 10);
|
||||||
|
|
||||||
memcpy(iov2, iov1, sizeof(iov1));
|
memcpy(iov2, iov1, sizeof(iov1));
|
||||||
|
|
||||||
span<file::iovec_t> iov = iov2;
|
span<iovec_t> iov = iov2;
|
||||||
|
|
||||||
// advance iov 13 bytes. Make sure what's left fits pattern 1 shifted
|
// advance iov 13 bytes. Make sure what's left fits pattern 1 shifted
|
||||||
// 13 bytes
|
// 13 bytes
|
||||||
|
@ -1098,7 +1098,7 @@ struct test_fileop : libtorrent::fileop
|
||||||
explicit test_fileop(int stripe_size) : m_stripe_size(stripe_size) {}
|
explicit test_fileop(int stripe_size) : m_stripe_size(stripe_size) {}
|
||||||
|
|
||||||
int file_op(file_index_t const file_index, std::int64_t const file_offset
|
int file_op(file_index_t const file_index, std::int64_t const file_offset
|
||||||
, span<file::iovec_t const> bufs, storage_error& ec) override
|
, span<iovec_t const> bufs, storage_error& ec) override
|
||||||
{
|
{
|
||||||
size_t offset = size_t(file_offset);
|
size_t offset = size_t(file_offset);
|
||||||
if (file_index >= m_file_data.end_index())
|
if (file_index >= m_file_data.end_index())
|
||||||
|
@ -1137,7 +1137,7 @@ struct test_read_fileop : fileop
|
||||||
explicit test_read_fileop(int size) : m_size(size), m_counter(0) {}
|
explicit test_read_fileop(int size) : m_size(size), m_counter(0) {}
|
||||||
|
|
||||||
int file_op(file_index_t const file_index, std::int64_t const file_offset
|
int file_op(file_index_t const file_index, std::int64_t const file_offset
|
||||||
, span<file::iovec_t const> bufs, storage_error& ec) override
|
, span<iovec_t const> bufs, storage_error& ec) override
|
||||||
{
|
{
|
||||||
int local_size = std::min(m_size, bufs_size(bufs));
|
int local_size = std::min(m_size, bufs_size(bufs));
|
||||||
const int read = local_size;
|
const int read = local_size;
|
||||||
|
@ -1168,7 +1168,7 @@ struct test_error_fileop : fileop
|
||||||
: m_error_file(error_file) {}
|
: m_error_file(error_file) {}
|
||||||
|
|
||||||
int file_op(file_index_t const file_index, std::int64_t const file_offset
|
int file_op(file_index_t const file_index, std::int64_t const file_offset
|
||||||
, span<file::iovec_t const> bufs, storage_error& ec) override
|
, span<iovec_t const> bufs, storage_error& ec) override
|
||||||
{
|
{
|
||||||
if (m_error_file == file_index)
|
if (m_error_file == file_index)
|
||||||
{
|
{
|
||||||
|
@ -1184,12 +1184,12 @@ struct test_error_fileop : fileop
|
||||||
file_index_t m_error_file;
|
file_index_t m_error_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
int count_bufs(file::iovec_t const* bufs, int bytes)
|
int count_bufs(iovec_t const* bufs, int bytes)
|
||||||
{
|
{
|
||||||
int size = 0;
|
int size = 0;
|
||||||
int count = 1;
|
int count = 1;
|
||||||
if (bytes == 0) return 0;
|
if (bytes == 0) return 0;
|
||||||
for (file::iovec_t const* i = bufs;; ++i, ++count)
|
for (iovec_t const* i = bufs;; ++i, ++count)
|
||||||
{
|
{
|
||||||
size += int(i->iov_len);
|
size += int(i->iov_len);
|
||||||
if (size >= bytes) return count;
|
if (size >= bytes) return count;
|
||||||
|
@ -1199,7 +1199,7 @@ int count_bufs(file::iovec_t const* bufs, int bytes)
|
||||||
TORRENT_TEST(readwritev_stripe_1)
|
TORRENT_TEST(readwritev_stripe_1)
|
||||||
{
|
{
|
||||||
const int num_bufs = 30;
|
const int num_bufs = 30;
|
||||||
file::iovec_t iov[num_bufs];
|
iovec_t iov[num_bufs];
|
||||||
|
|
||||||
alloc_iov(iov, num_bufs);
|
alloc_iov(iov, num_bufs);
|
||||||
fill_pattern(iov, num_bufs);
|
fill_pattern(iov, num_bufs);
|
||||||
|
@ -1210,7 +1210,7 @@ TORRENT_TEST(readwritev_stripe_1)
|
||||||
|
|
||||||
TEST_CHECK(bufs_size({iov, size_t(num_bufs)}) >= fs.total_size());
|
TEST_CHECK(bufs_size({iov, size_t(num_bufs)}) >= fs.total_size());
|
||||||
|
|
||||||
file::iovec_t iov2[num_bufs];
|
iovec_t iov2[num_bufs];
|
||||||
copy_bufs(iov, int(fs.total_size()), iov2);
|
copy_bufs(iov, int(fs.total_size()), iov2);
|
||||||
int num_bufs2 = count_bufs(iov2, int(fs.total_size()));
|
int num_bufs2 = count_bufs(iov2, int(fs.total_size()));
|
||||||
TEST_CHECK(num_bufs2 <= num_bufs);
|
TEST_CHECK(num_bufs2 <= num_bufs);
|
||||||
|
@ -1239,7 +1239,7 @@ TORRENT_TEST(readwritev_single_buffer)
|
||||||
storage_error ec;
|
storage_error ec;
|
||||||
|
|
||||||
std::vector<char> buf(size_t(fs.total_size()));
|
std::vector<char> buf(size_t(fs.total_size()));
|
||||||
file::iovec_t iov = { &buf[0], buf.size() };
|
iovec_t iov = { &buf[0], buf.size() };
|
||||||
fill_pattern(&iov, 1);
|
fill_pattern(&iov, 1);
|
||||||
|
|
||||||
int ret = readwritev(fs, iov, piece_index_t(0), 0, fop, ec);
|
int ret = readwritev(fs, iov, piece_index_t(0), 0, fop, ec);
|
||||||
|
@ -1264,7 +1264,7 @@ TORRENT_TEST(readwritev_read)
|
||||||
storage_error ec;
|
storage_error ec;
|
||||||
|
|
||||||
std::vector<char> buf(size_t(fs.total_size()));
|
std::vector<char> buf(size_t(fs.total_size()));
|
||||||
file::iovec_t iov = { &buf[0], buf.size() };
|
iovec_t iov = { &buf[0], buf.size() };
|
||||||
|
|
||||||
// read everything
|
// read everything
|
||||||
int ret = readwritev(fs, iov, piece_index_t(0), 0, fop, ec);
|
int ret = readwritev(fs, iov, piece_index_t(0), 0, fop, ec);
|
||||||
|
@ -1280,7 +1280,7 @@ TORRENT_TEST(readwritev_read_short)
|
||||||
storage_error ec;
|
storage_error ec;
|
||||||
|
|
||||||
std::vector<char> buf(size_t(fs.total_size()));
|
std::vector<char> buf(size_t(fs.total_size()));
|
||||||
file::iovec_t iov = { &buf[0]
|
iovec_t iov = { &buf[0]
|
||||||
, static_cast<size_t>(fs.total_size()) };
|
, static_cast<size_t>(fs.total_size()) };
|
||||||
|
|
||||||
// read everything
|
// read everything
|
||||||
|
@ -1300,7 +1300,7 @@ TORRENT_TEST(readwritev_error)
|
||||||
storage_error ec;
|
storage_error ec;
|
||||||
|
|
||||||
std::vector<char> buf(size_t(fs.total_size()));
|
std::vector<char> buf(size_t(fs.total_size()));
|
||||||
file::iovec_t iov = { &buf[0]
|
iovec_t iov = { &buf[0]
|
||||||
, static_cast<size_t>(fs.total_size()) };
|
, static_cast<size_t>(fs.total_size()) };
|
||||||
|
|
||||||
// read everything
|
// read everything
|
||||||
|
@ -1327,7 +1327,7 @@ TORRENT_TEST(readwritev_zero_size_files)
|
||||||
storage_error ec;
|
storage_error ec;
|
||||||
|
|
||||||
std::vector<char> buf(size_t(fs.total_size()));
|
std::vector<char> buf(size_t(fs.total_size()));
|
||||||
file::iovec_t iov = { &buf[0]
|
iovec_t iov = { &buf[0]
|
||||||
, static_cast<size_t>(fs.total_size()) };
|
, static_cast<size_t>(fs.total_size()) };
|
||||||
|
|
||||||
// read everything
|
// read everything
|
||||||
|
@ -1364,7 +1364,7 @@ TORRENT_TEST(move_storage_to_self)
|
||||||
disk_buffer_pool dp(16 * 1024, ios, std::bind(&nop));
|
disk_buffer_pool dp(16 * 1024, ios, std::bind(&nop));
|
||||||
std::shared_ptr<default_storage> s = setup_torrent(fs, fp, buf, save_path, set);
|
std::shared_ptr<default_storage> s = setup_torrent(fs, fp, buf, save_path, set);
|
||||||
|
|
||||||
file::iovec_t const b = {&buf[0], 4};
|
iovec_t const b = {&buf[0], 4};
|
||||||
storage_error se;
|
storage_error se;
|
||||||
s->writev(b, piece_index_t(1), 0, 0, se);
|
s->writev(b, piece_index_t(1), 0, 0, se);
|
||||||
|
|
||||||
|
@ -1393,7 +1393,7 @@ TORRENT_TEST(move_storage_into_self)
|
||||||
disk_buffer_pool dp(16 * 1024, ios, std::bind(&nop));
|
disk_buffer_pool dp(16 * 1024, ios, std::bind(&nop));
|
||||||
std::shared_ptr<default_storage> s = setup_torrent(fs, fp, buf, save_path, set);
|
std::shared_ptr<default_storage> s = setup_torrent(fs, fp, buf, save_path, set);
|
||||||
|
|
||||||
file::iovec_t const b = {&buf[0], 4};
|
iovec_t const b = {&buf[0], 4};
|
||||||
storage_error se;
|
storage_error se;
|
||||||
s->writev(b, piece_index_t(2), 0, 0, se);
|
s->writev(b, piece_index_t(2), 0, 0, se);
|
||||||
|
|
||||||
|
@ -1439,7 +1439,7 @@ TORRENT_TEST(dont_move_intermingled_files)
|
||||||
disk_buffer_pool dp(16 * 1024, ios, std::bind(&nop));
|
disk_buffer_pool dp(16 * 1024, ios, std::bind(&nop));
|
||||||
std::shared_ptr<default_storage> s = setup_torrent(fs, fp, buf, save_path, set);
|
std::shared_ptr<default_storage> s = setup_torrent(fs, fp, buf, save_path, set);
|
||||||
|
|
||||||
file::iovec_t b = {&buf[0], 4};
|
iovec_t b = {&buf[0], 4};
|
||||||
storage_error se;
|
storage_error se;
|
||||||
s->writev(b, piece_index_t(2), 0, 0, se);
|
s->writev(b, piece_index_t(2), 0, 0, se);
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct test_storage : default_storage
|
||||||
}
|
}
|
||||||
|
|
||||||
int writev(
|
int writev(
|
||||||
span<file::iovec_t const> bufs
|
span<iovec_t const> bufs
|
||||||
, piece_index_t piece_index
|
, piece_index_t piece_index
|
||||||
, int offset
|
, int offset
|
||||||
, int flags
|
, int flags
|
||||||
|
|
|
@ -58,7 +58,7 @@ TORRENT_TEST(web_seed_redirect)
|
||||||
TEST_ERROR("failed to create file");
|
TEST_ERROR("failed to create file");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file::iovec_t b = { random_data, size_t(16000)};
|
iovec_t b = { random_data, size_t(16000)};
|
||||||
f.writev(0, b, ec);
|
f.writev(0, b, ec);
|
||||||
fs.add_file("test_file", 16000);
|
fs.add_file("test_file", 16000);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue