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