2014-07-06 21:18:00 +02:00
|
|
|
/*
|
|
|
|
|
2016-01-18 00:57:46 +01:00
|
|
|
Copyright (c) 2010-2016, Arvid Norberg
|
2014-07-06 21:18:00 +02:00
|
|
|
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_DISK_IO_JOB_HPP
|
|
|
|
#define TORRENT_DISK_IO_JOB_HPP
|
|
|
|
|
|
|
|
#include "libtorrent/error_code.hpp"
|
|
|
|
#include "libtorrent/tailqueue.hpp"
|
2016-11-21 05:58:48 +01:00
|
|
|
#include "libtorrent/peer_request.hpp"
|
2016-11-18 06:25:27 +01:00
|
|
|
#include "libtorrent/aux_/block_cache_reference.hpp"
|
2016-11-21 05:58:48 +01:00
|
|
|
#include "libtorrent/sha1_hash.hpp"
|
2016-11-26 07:51:47 +01:00
|
|
|
#include "libtorrent/disk_interface.hpp"
|
2016-12-22 16:42:33 +01:00
|
|
|
#include "libtorrent/aux_/vector.hpp"
|
|
|
|
#include "libtorrent/units.hpp"
|
2016-11-21 05:58:48 +01:00
|
|
|
|
|
|
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
|
|
|
#include <boost/variant/variant.hpp>
|
|
|
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
2015-04-18 04:33:39 +02:00
|
|
|
|
2016-08-17 23:26:35 +02:00
|
|
|
#include <string>
|
2016-08-29 14:31:23 +02:00
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
|
|
|
#include <functional>
|
2015-04-18 04:33:39 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
namespace libtorrent
|
|
|
|
{
|
2016-11-13 03:45:30 +01:00
|
|
|
struct storage_interface;
|
2014-07-06 21:18:00 +02:00
|
|
|
struct cached_piece_entry;
|
2015-05-30 23:46:59 +02:00
|
|
|
class torrent_info;
|
2016-02-15 00:17:32 +01:00
|
|
|
struct add_torrent_params;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// disk_io_jobs are allocated in a pool allocator in disk_io_thread
|
|
|
|
// they are always allocated from the network thread, posted
|
|
|
|
// (as pointers) to the disk I/O thread, and then passed back
|
|
|
|
// to the network thread for completion handling and to be freed.
|
|
|
|
// each disk_io_job can belong to one tailqueue. The job queue
|
|
|
|
// in the disk thread, is one, the jobs waiting on completion
|
|
|
|
// on a cache piece (in block_cache) is another, and a job
|
|
|
|
// waiting for a storage fence to be lowered is another. Jobs
|
|
|
|
// are never in more than one queue at a time. Only passing around
|
|
|
|
// pointers and chaining them back and forth into lists saves
|
|
|
|
// a lot of heap allocation churn of using general purpose
|
|
|
|
// containers.
|
2015-08-19 15:22:00 +02:00
|
|
|
struct TORRENT_EXTRA_EXPORT disk_io_job : tailqueue_node<disk_io_job>
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
disk_io_job();
|
|
|
|
~disk_io_job();
|
2016-10-27 02:41:57 +02:00
|
|
|
disk_io_job(disk_io_job const&) = delete;
|
|
|
|
disk_io_job& operator=(disk_io_job const&) = delete;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-11-21 05:58:48 +01:00
|
|
|
void call_callback();
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
enum action_t : std::uint8_t
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
read
|
|
|
|
, write
|
|
|
|
, hash
|
|
|
|
, move_storage
|
|
|
|
, release_files
|
|
|
|
, delete_files
|
|
|
|
, check_fastresume
|
|
|
|
, rename_file
|
|
|
|
, stop_torrent
|
|
|
|
, flush_piece
|
|
|
|
, flush_hashed
|
|
|
|
, flush_storage
|
|
|
|
, trim_cache
|
2015-08-20 22:28:00 +02:00
|
|
|
, file_priority
|
2014-07-06 21:18:00 +02:00
|
|
|
, clear_piece
|
2015-03-21 01:12:40 +01:00
|
|
|
, resolve_links
|
2014-07-06 21:18:00 +02:00
|
|
|
, num_job_ids
|
|
|
|
};
|
|
|
|
|
|
|
|
enum flags_t
|
|
|
|
{
|
|
|
|
// force making a copy of the cached block, rather
|
|
|
|
// than getting a reference to the block already in
|
|
|
|
// the cache.
|
|
|
|
force_copy = 0x4,
|
|
|
|
|
|
|
|
// this is set by the storage object when a fence is raised
|
|
|
|
// for this job. It means that this no other jobs on the same
|
|
|
|
// storage will execute in parallel with this one. It's used
|
|
|
|
// to lower the fence when the job has completed
|
|
|
|
fence = 0x8,
|
|
|
|
|
|
|
|
// this job is currently being performed, or it's hanging
|
|
|
|
// on a cache piece that may be flushed soon
|
2016-03-20 16:38:55 +01:00
|
|
|
in_progress = 0x20
|
2014-07-06 21:18:00 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// for write jobs, returns true if its block
|
|
|
|
// is not dirty anymore
|
|
|
|
bool completed(cached_piece_entry const* pe, int block_size);
|
|
|
|
|
|
|
|
// unique identifier for the peer when reading
|
2016-10-27 02:41:57 +02:00
|
|
|
void* requester = nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// for write, this points to the data to write,
|
|
|
|
// for read, the data read is returned here
|
|
|
|
// for other jobs, it may point to other job-specific types
|
|
|
|
// for move_storage and rename_file this is a string allocated
|
|
|
|
// with malloc()
|
|
|
|
// for get_cache_info this points to a cache_status object which
|
|
|
|
// is filled in
|
2015-05-16 22:41:37 +02:00
|
|
|
union
|
|
|
|
{
|
|
|
|
char* disk_block;
|
|
|
|
char* string;
|
2016-02-15 00:17:32 +01:00
|
|
|
add_torrent_params const* check_resume_data;
|
2016-12-22 16:42:33 +01:00
|
|
|
aux::vector<std::uint8_t, file_index_t>* priorities;
|
2016-03-13 08:50:37 +01:00
|
|
|
int delete_options;
|
2015-05-16 22:41:37 +02:00
|
|
|
} buffer;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// the disk storage this job applies to (if applicable)
|
2016-11-13 03:45:30 +01:00
|
|
|
std::shared_ptr<storage_interface> storage;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// this is called when operation completes
|
2016-11-21 05:58:48 +01:00
|
|
|
|
|
|
|
using read_handler = std::function<void(aux::block_cache_reference ref
|
|
|
|
, char* block, int flags, storage_error const& se)>;
|
|
|
|
using write_handler = std::function<void(storage_error const&)>;
|
2016-12-22 16:42:33 +01:00
|
|
|
using hash_handler = std::function<void(piece_index_t, sha1_hash const&, storage_error const&)>;
|
2016-11-26 07:51:47 +01:00
|
|
|
using move_handler = std::function<void(status_t, std::string const&, storage_error const&)>;
|
2016-11-22 07:48:14 +01:00
|
|
|
using release_handler = std::function<void()>;
|
2016-11-26 07:51:47 +01:00
|
|
|
using check_handler = std::function<void(status_t, storage_error const&)>;
|
2016-12-22 16:42:33 +01:00
|
|
|
using rename_handler = std::function<void(std::string const&, file_index_t, storage_error const&)>;
|
|
|
|
using clear_piece_handler = std::function<void(piece_index_t)>;
|
2016-11-21 05:58:48 +01:00
|
|
|
|
2016-11-22 07:48:14 +01:00
|
|
|
boost::variant<read_handler
|
|
|
|
, write_handler
|
|
|
|
, hash_handler
|
|
|
|
, move_handler
|
|
|
|
, release_handler
|
2016-11-23 01:03:27 +01:00
|
|
|
, check_handler
|
2016-11-23 07:43:57 +01:00
|
|
|
, rename_handler
|
|
|
|
, clear_piece_handler> callback;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// the error code from the file operation
|
|
|
|
// on error, this also contains the path of the
|
|
|
|
// file the disk operation failed on
|
|
|
|
storage_error error;
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
// result for hash jobs
|
|
|
|
char piece_hash[20];
|
|
|
|
|
2015-03-21 01:12:40 +01:00
|
|
|
// this is used for check_fastresume to pass in a vector of hard-links
|
|
|
|
// to create. Each element corresponds to a file in the file_storage.
|
|
|
|
// The string is the absolute path of the identical file to create
|
|
|
|
// the hard link to.
|
2016-12-22 16:42:33 +01:00
|
|
|
aux::vector<std::string, file_index_t>* links;
|
2015-03-21 01:12:40 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
struct io_args
|
|
|
|
{
|
|
|
|
// if this is set, the read operation is required to
|
|
|
|
// release the block references once it's done sending
|
|
|
|
// the buffer. For aligned block requests (by far the
|
|
|
|
// most common) the buffers are not actually copied
|
|
|
|
// into the send buffer, but simply referenced. When this
|
|
|
|
// is set in a response to a read, the buffer needs to
|
|
|
|
// be de-referenced by sending a reclaim_block message
|
|
|
|
// back to the disk thread
|
2016-11-18 06:25:27 +01:00
|
|
|
aux::block_cache_reference ref;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// for read and write, the offset into the piece
|
|
|
|
// the read or write should start
|
|
|
|
// for hash jobs, this is the first block the hash
|
|
|
|
// job is still holding a reference to. The end of
|
|
|
|
// the range of blocks a hash jobs holds references
|
|
|
|
// to is always the last block in the piece.
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint32_t offset;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// number of bytes 'buffer' points to. Used for read & write
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint16_t buffer_size;
|
2014-07-06 21:18:00 +02:00
|
|
|
} io;
|
|
|
|
} d;
|
|
|
|
|
|
|
|
// arguments used for read and write
|
|
|
|
// the piece this job applies to
|
2016-12-22 16:42:33 +01:00
|
|
|
union {
|
|
|
|
piece_index_t piece;
|
|
|
|
file_index_t file_index;
|
|
|
|
};
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// the type of job this is
|
2016-12-22 16:42:33 +01:00
|
|
|
action_t action;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// return value of operation
|
2016-11-26 07:51:47 +01:00
|
|
|
status_t ret = status_t::no_error;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// flags controlling this job
|
2016-10-27 02:41:57 +02:00
|
|
|
std::uint8_t flags = 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-06-18 14:31:07 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2016-10-27 02:41:57 +02:00
|
|
|
bool in_use = false;
|
2015-05-16 22:41:37 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// set to true when the job is added to the completion queue.
|
|
|
|
// to make sure we don't add it twice
|
2016-10-27 02:41:57 +02:00
|
|
|
mutable bool job_posted = false;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// set to true when the callback has been called once
|
|
|
|
// used to make sure we don't call it twice
|
2016-10-27 02:41:57 +02:00
|
|
|
mutable bool callback_called = false;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// this is true when the job is blocked by a storage_fence
|
2016-10-27 02:41:57 +02:00
|
|
|
mutable bool blocked = false;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // TORRENT_DISK_IO_JOB_HPP
|