1 /*
2 
3 Copyright (c) 2010-2018, Arvid Norberg
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the distribution.
15     * Neither the name of the author nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 
33 #ifndef TORRENT_DISK_IO_JOB_HPP
34 #define TORRENT_DISK_IO_JOB_HPP
35 
36 #include "libtorrent/fwd.hpp"
37 #include "libtorrent/error_code.hpp"
38 #include "libtorrent/tailqueue.hpp"
39 #include "libtorrent/sha1_hash.hpp"
40 #include "libtorrent/disk_interface.hpp"
41 #include "libtorrent/aux_/vector.hpp"
42 #include "libtorrent/units.hpp"
43 #include "libtorrent/session_types.hpp"
44 #include "libtorrent/flags.hpp"
45 
46 #include "libtorrent/aux_/disable_warnings_push.hpp"
47 #include <boost/variant/variant.hpp>
48 #include "libtorrent/aux_/disable_warnings_pop.hpp"
49 
50 #include <string>
51 #include <vector>
52 #include <memory>
53 #include <functional>
54 
55 namespace libtorrent {
56 
57 	struct cached_piece_entry;
58 
59 	// internal
60 	enum class job_action_t : std::uint8_t
61 	{
62 		read
63 		, write
64 		, hash
65 		, move_storage
66 		, release_files
67 		, delete_files
68 		, check_fastresume
69 		, rename_file
70 		, stop_torrent
71 		, flush_piece
72 		, flush_hashed
73 		, flush_storage
74 		, trim_cache
75 		, file_priority
76 		, clear_piece
77 		, num_job_ids
78 	};
79 
80 	// disk_io_jobs are allocated in a pool allocator in disk_io_thread
81 	// they are always allocated from the network thread, posted
82 	// (as pointers) to the disk I/O thread, and then passed back
83 	// to the network thread for completion handling and to be freed.
84 	// each disk_io_job can belong to one tailqueue. The job queue
85 	// in the disk thread, is one, the jobs waiting on completion
86 	// on a cache piece (in block_cache) is another, and a job
87 	// waiting for a storage fence to be lowered is another. Jobs
88 	// are never in more than one queue at a time. Only passing around
89 	// pointers and chaining them back and forth into lists saves
90 	// a lot of heap allocation churn of using general purpose
91 	// containers.
92 	struct TORRENT_EXTRA_EXPORT disk_io_job : tailqueue_node<disk_io_job>
93 	{
94 		disk_io_job();
95 		disk_io_job(disk_io_job const&) = delete;
96 		disk_io_job& operator=(disk_io_job const&) = delete;
97 
98 		void call_callback();
99 
100 		// this is set by the storage object when a fence is raised
101 		// for this job. It means that this no other jobs on the same
102 		// storage will execute in parallel with this one. It's used
103 		// to lower the fence when the job has completed
104 		static constexpr disk_job_flags_t fence = 1_bit;
105 
106 		// this job is currently being performed, or it's hanging
107 		// on a cache piece that may be flushed soon
108 		static constexpr disk_job_flags_t in_progress = 2_bit;
109 
110 		// this is set for jobs that we're no longer interested in. Any aborted
111 		// job that's executed should immediately fail with operation_aborted
112 		// instead of executing
113 		static constexpr disk_job_flags_t aborted = 6_bit;
114 
115 		// for write jobs, returns true if its block
116 		// is not dirty anymore
117 		bool completed(cached_piece_entry const* pe);
118 
119 		// for read and write, this is the disk_buffer_holder
120 		// for other jobs, it may point to other job-specific types
121 		// for move_storage and rename_file this is a string
122 		boost::variant<disk_buffer_holder
123 			, std::string
124 			, add_torrent_params const*
125 			, aux::vector<download_priority_t, file_index_t>
126 			, remove_flags_t
127 			> argument;
128 
129 		// the disk storage this job applies to (if applicable)
130 		std::shared_ptr<storage_interface> storage;
131 
132 		// this is called when operation completes
133 
134 		using read_handler = std::function<void(disk_buffer_holder block, disk_job_flags_t flags, storage_error const& se)>;
135 		using write_handler = std::function<void(storage_error const&)>;
136 		using hash_handler = std::function<void(piece_index_t, sha1_hash const&, storage_error const&)>;
137 		using move_handler = std::function<void(status_t, std::string, storage_error const&)>;
138 		using release_handler = std::function<void()>;
139 		using check_handler = std::function<void(status_t, storage_error const&)>;
140 		using rename_handler = std::function<void(std::string, file_index_t, storage_error const&)>;
141 		using clear_piece_handler = std::function<void(piece_index_t)>;
142 		using set_file_prio_handler = std::function<void(storage_error const&, aux::vector<download_priority_t, file_index_t>)>;
143 
144 		boost::variant<read_handler
145 			, write_handler
146 			, hash_handler
147 			, move_handler
148 			, release_handler
149 			, check_handler
150 			, rename_handler
151 			, clear_piece_handler
152 			, set_file_prio_handler> callback;
153 
154 		// the error code from the file operation
155 		// on error, this also contains the path of the
156 		// file the disk operation failed on
157 		storage_error error;
158 
159 		union un
160 		{
un()161 			un() {}
162 			// result for hash jobs
163 			sha1_hash piece_hash;
164 
165 			// this is used for check_fastresume to pass in a vector of hard-links
166 			// to create. Each element corresponds to a file in the file_storage.
167 			// The string is the absolute path of the identical file to create
168 			// the hard link to.
169 			aux::vector<std::string, file_index_t>* links;
170 
171 			struct io_args
172 			{
173 			// for read and write, the offset into the piece
174 			// the read or write should start
175 			// for hash jobs, this is the first block the hash
176 			// job is still holding a reference to. The end of
177 			// the range of blocks a hash jobs holds references
178 			// to is always the last block in the piece.
179 			std::int32_t offset;
180 
181 			// number of bytes 'buffer' points to. Used for read & write
182 			std::uint16_t buffer_size;
183 			} io;
184 		} d;
185 
186 		// arguments used for read and write
187 		// the piece this job applies to
188 		union {
189 			piece_index_t piece;
190 			file_index_t file_index;
191 		};
192 
193 		// the type of job this is
194 		job_action_t action = job_action_t::read;
195 
196 		// return value of operation
197 		status_t ret = status_t::no_error;
198 
199 		// flags controlling this job
200 		disk_job_flags_t flags = disk_job_flags_t{};
201 
202 		move_flags_t move_flags = move_flags_t::always_replace_files;
203 
204 #if TORRENT_USE_ASSERTS
205 		bool in_use = false;
206 
207 		// set to true when the job is added to the completion queue.
208 		// to make sure we don't add it twice
209 		mutable bool job_posted = false;
210 
211 		// set to true when the callback has been called once
212 		// used to make sure we don't call it twice
213 		mutable bool callback_called = false;
214 
215 		// this is true when the job is blocked by a storage_fence
216 		mutable bool blocked = false;
217 #endif
218 	};
219 
220 }
221 
222 #endif // TORRENT_DISK_IO_JOB_HPP
223