added an asynchronous save_resume_data to make it easier to synchronize with the disk IO thread

This commit is contained in:
Arvid Norberg 2008-04-13 18:54:36 +00:00
parent 6639f72804
commit 3fea2080fd
12 changed files with 657 additions and 438 deletions

View File

@ -24,146 +24,147 @@
<div class="contents topic" id="table-of-contents">
<p class="topic-title first">Table of contents</p>
<ul class="simple">
<li><a class="reference internal" href="#overview" id="id18">overview</a></li>
<li><a class="reference internal" href="#network-primitives" id="id19">network primitives</a></li>
<li><a class="reference internal" href="#session" id="id20">session</a><ul>
<li><a class="reference internal" href="#id1" id="id21">session()</a></li>
<li><a class="reference internal" href="#id2" id="id22">~session()</a></li>
<li><a class="reference internal" href="#abort" id="id23">abort()</a></li>
<li><a class="reference internal" href="#add-torrent" id="id24">add_torrent()</a></li>
<li><a class="reference internal" href="#remove-torrent" id="id25">remove_torrent()</a></li>
<li><a class="reference internal" href="#find-torrent-get-torrents" id="id26">find_torrent() get_torrents()</a></li>
<li><a class="reference internal" href="#set-upload-rate-limit-set-download-rate-limit-upload-rate-limit-download-rate-limit" id="id27">set_upload_rate_limit() set_download_rate_limit() upload_rate_limit() download_rate_limit()</a></li>
<li><a class="reference internal" href="#set-max-uploads-set-max-connections" id="id28">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference internal" href="#num-uploads-num-connections" id="id29">num_uploads() num_connections()</a></li>
<li><a class="reference internal" href="#set-max-half-open-connections-max-half-open-connections" id="id30">set_max_half_open_connections() max_half_open_connections()</a></li>
<li><a class="reference internal" href="#load-asnum-db-load-country-db" id="id31">load_asnum_db() load_country_db()</a></li>
<li><a class="reference internal" href="#load-state-state" id="id32">load_state() state()</a></li>
<li><a class="reference internal" href="#set-ip-filter" id="id33">set_ip_filter()</a></li>
<li><a class="reference internal" href="#status" id="id34">status()</a></li>
<li><a class="reference internal" href="#get-cache-status" id="id35">get_cache_status()</a></li>
<li><a class="reference internal" href="#get-cache-info" id="id36">get_cache_info()</a></li>
<li><a class="reference internal" href="#is-listening-listen-port-listen-on" id="id37">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference internal" href="#pop-alert-set-severity-level" id="id38">pop_alert() set_severity_level()</a></li>
<li><a class="reference internal" href="#add-extension" id="id39">add_extension()</a></li>
<li><a class="reference internal" href="#set-settings-set-pe-settings" id="id40">set_settings() set_pe_settings()</a></li>
<li><a class="reference internal" href="#set-peer-proxy-set-web-seed-proxy-set-tracker-proxy-set-dht-proxy" id="id41">set_peer_proxy() set_web_seed_proxy() set_tracker_proxy() set_dht_proxy()</a></li>
<li><a class="reference internal" href="#peer-proxy-web-seed-proxy-tracker-proxy-dht-proxy" id="id42">peer_proxy() web_seed_proxy() tracker_proxy() dht_proxy()</a></li>
<li><a class="reference internal" href="#start-dht-stop-dht-set-dht-settings-dht-state" id="id43">start_dht() stop_dht() set_dht_settings() dht_state()</a></li>
<li><a class="reference internal" href="#add-dht-node-add-dht-router" id="id44">add_dht_node() add_dht_router()</a></li>
<li><a class="reference internal" href="#start-lsd-stop-lsd" id="id45">start_lsd() stop_lsd()</a></li>
<li><a class="reference internal" href="#start-upnp-stop-upnp" id="id46">start_upnp() stop_upnp()</a></li>
<li><a class="reference internal" href="#start-natpmp-stop-natpmp" id="id47">start_natpmp() stop_natpmp()</a></li>
<li><a class="reference internal" href="#overview" id="id17">overview</a></li>
<li><a class="reference internal" href="#network-primitives" id="id18">network primitives</a></li>
<li><a class="reference internal" href="#session" id="id19">session</a><ul>
<li><a class="reference internal" href="#id1" id="id20">session()</a></li>
<li><a class="reference internal" href="#id2" id="id21">~session()</a></li>
<li><a class="reference internal" href="#abort" id="id22">abort()</a></li>
<li><a class="reference internal" href="#add-torrent" id="id23">add_torrent()</a></li>
<li><a class="reference internal" href="#remove-torrent" id="id24">remove_torrent()</a></li>
<li><a class="reference internal" href="#find-torrent-get-torrents" id="id25">find_torrent() get_torrents()</a></li>
<li><a class="reference internal" href="#set-upload-rate-limit-set-download-rate-limit-upload-rate-limit-download-rate-limit" id="id26">set_upload_rate_limit() set_download_rate_limit() upload_rate_limit() download_rate_limit()</a></li>
<li><a class="reference internal" href="#set-max-uploads-set-max-connections" id="id27">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference internal" href="#num-uploads-num-connections" id="id28">num_uploads() num_connections()</a></li>
<li><a class="reference internal" href="#set-max-half-open-connections-max-half-open-connections" id="id29">set_max_half_open_connections() max_half_open_connections()</a></li>
<li><a class="reference internal" href="#load-asnum-db-load-country-db" id="id30">load_asnum_db() load_country_db()</a></li>
<li><a class="reference internal" href="#load-state-state" id="id31">load_state() state()</a></li>
<li><a class="reference internal" href="#set-ip-filter" id="id32">set_ip_filter()</a></li>
<li><a class="reference internal" href="#status" id="id33">status()</a></li>
<li><a class="reference internal" href="#get-cache-status" id="id34">get_cache_status()</a></li>
<li><a class="reference internal" href="#get-cache-info" id="id35">get_cache_info()</a></li>
<li><a class="reference internal" href="#is-listening-listen-port-listen-on" id="id36">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference internal" href="#pop-alert-set-severity-level" id="id37">pop_alert() set_severity_level()</a></li>
<li><a class="reference internal" href="#add-extension" id="id38">add_extension()</a></li>
<li><a class="reference internal" href="#set-settings-set-pe-settings" id="id39">set_settings() set_pe_settings()</a></li>
<li><a class="reference internal" href="#set-peer-proxy-set-web-seed-proxy-set-tracker-proxy-set-dht-proxy" id="id40">set_peer_proxy() set_web_seed_proxy() set_tracker_proxy() set_dht_proxy()</a></li>
<li><a class="reference internal" href="#peer-proxy-web-seed-proxy-tracker-proxy-dht-proxy" id="id41">peer_proxy() web_seed_proxy() tracker_proxy() dht_proxy()</a></li>
<li><a class="reference internal" href="#start-dht-stop-dht-set-dht-settings-dht-state" id="id42">start_dht() stop_dht() set_dht_settings() dht_state()</a></li>
<li><a class="reference internal" href="#add-dht-node-add-dht-router" id="id43">add_dht_node() add_dht_router()</a></li>
<li><a class="reference internal" href="#start-lsd-stop-lsd" id="id44">start_lsd() stop_lsd()</a></li>
<li><a class="reference internal" href="#start-upnp-stop-upnp" id="id45">start_upnp() stop_upnp()</a></li>
<li><a class="reference internal" href="#start-natpmp-stop-natpmp" id="id46">start_natpmp() stop_natpmp()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#entry" id="id48">entry</a><ul>
<li><a class="reference internal" href="#integer-string-list-dict-type" id="id49">integer() string() list() dict() type()</a></li>
<li><a class="reference internal" href="#operator" id="id50">operator[]</a></li>
<li><a class="reference internal" href="#find-key" id="id51">find_key()</a></li>
<li><a class="reference internal" href="#entry" id="id47">entry</a><ul>
<li><a class="reference internal" href="#integer-string-list-dict-type" id="id48">integer() string() list() dict() type()</a></li>
<li><a class="reference internal" href="#operator" id="id49">operator[]</a></li>
<li><a class="reference internal" href="#find-key" id="id50">find_key()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-info" id="id52">torrent_info</a><ul>
<li><a class="reference internal" href="#id3" id="id53">torrent_info()</a></li>
<li><a class="reference internal" href="#set-comment-set-piece-size-set-creator-set-hash-add-tracker-add-file" id="id54">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</a></li>
<li><a class="reference internal" href="#create-torrent" id="id55">create_torrent()</a></li>
<li><a class="reference internal" href="#remap-files" id="id56">remap_files()</a></li>
<li><a class="reference internal" href="#begin-files-end-files-rbegin-files-rend-files" id="id57">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference internal" href="#num-files-file-at" id="id58">num_files() file_at()</a></li>
<li><a class="reference internal" href="#map-block" id="id59">map_block()</a></li>
<li><a class="reference internal" href="#map-file" id="id60">map_file()</a></li>
<li><a class="reference internal" href="#url-seeds-add-url-seed" id="id61">url_seeds() add_url_seed()</a></li>
<li><a class="reference internal" href="#print" id="id62">print()</a></li>
<li><a class="reference internal" href="#trackers" id="id63">trackers()</a></li>
<li><a class="reference internal" href="#total-size-piece-length-piece-size-num-pieces" id="id64">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference internal" href="#hash-for-piece-info-hash" id="id65">hash_for_piece() info_hash()</a></li>
<li><a class="reference internal" href="#name-comment-creation-date-creator" id="id66">name() comment() creation_date() creator()</a></li>
<li><a class="reference internal" href="#priv-set-priv" id="id67">priv() set_priv()</a></li>
<li><a class="reference internal" href="#nodes" id="id68">nodes()</a></li>
<li><a class="reference internal" href="#add-node" id="id69">add_node()</a></li>
<li><a class="reference internal" href="#torrent-info" id="id51">torrent_info</a><ul>
<li><a class="reference internal" href="#id3" id="id52">torrent_info()</a></li>
<li><a class="reference internal" href="#set-comment-set-piece-size-set-creator-set-hash-add-tracker-add-file" id="id53">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</a></li>
<li><a class="reference internal" href="#create-torrent" id="id54">create_torrent()</a></li>
<li><a class="reference internal" href="#remap-files" id="id55">remap_files()</a></li>
<li><a class="reference internal" href="#begin-files-end-files-rbegin-files-rend-files" id="id56">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference internal" href="#num-files-file-at" id="id57">num_files() file_at()</a></li>
<li><a class="reference internal" href="#map-block" id="id58">map_block()</a></li>
<li><a class="reference internal" href="#map-file" id="id59">map_file()</a></li>
<li><a class="reference internal" href="#url-seeds-add-url-seed" id="id60">url_seeds() add_url_seed()</a></li>
<li><a class="reference internal" href="#print" id="id61">print()</a></li>
<li><a class="reference internal" href="#trackers" id="id62">trackers()</a></li>
<li><a class="reference internal" href="#total-size-piece-length-piece-size-num-pieces" id="id63">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference internal" href="#hash-for-piece-info-hash" id="id64">hash_for_piece() info_hash()</a></li>
<li><a class="reference internal" href="#name-comment-creation-date-creator" id="id65">name() comment() creation_date() creator()</a></li>
<li><a class="reference internal" href="#priv-set-priv" id="id66">priv() set_priv()</a></li>
<li><a class="reference internal" href="#nodes" id="id67">nodes()</a></li>
<li><a class="reference internal" href="#add-node" id="id68">add_node()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-handle" id="id70">torrent_handle</a><ul>
<li><a class="reference internal" href="#piece-priority-prioritize-pieces-piece-priorities-prioritize-files" id="id71">piece_priority() prioritize_pieces() piece_priorities() prioritize_files()</a></li>
<li><a class="reference internal" href="#file-progress" id="id72">file_progress()</a></li>
<li><a class="reference internal" href="#save-path" id="id73">save_path()</a></li>
<li><a class="reference internal" href="#move-storage" id="id74">move_storage()</a></li>
<li><a class="reference internal" href="#force-reannounce" id="id75">force_reannounce()</a></li>
<li><a class="reference internal" href="#scrape-tracker" id="id76">scrape_tracker()</a></li>
<li><a class="reference internal" href="#connect-peer" id="id77">connect_peer()</a></li>
<li><a class="reference internal" href="#name" id="id78">name()</a></li>
<li><a class="reference internal" href="#set-ratio" id="id79">set_ratio()</a></li>
<li><a class="reference internal" href="#set-upload-limit-set-download-limit-upload-limit-download-limit" id="id80">set_upload_limit() set_download_limit() upload_limit() download_limit()</a></li>
<li><a class="reference internal" href="#set-sequential-download" id="id81">set_sequential_download()</a></li>
<li><a class="reference internal" href="#set-peer-upload-limit-set-peer-download-limit" id="id82">set_peer_upload_limit() set_peer_download_limit()</a></li>
<li><a class="reference internal" href="#pause-resume-is-paused" id="id83">pause() resume() is_paused()</a></li>
<li><a class="reference internal" href="#resolve-countries" id="id84">resolve_countries()</a></li>
<li><a class="reference internal" href="#is-seed" id="id85">is_seed()</a></li>
<li><a class="reference internal" href="#has-metadata" id="id86">has_metadata()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id87">set_tracker_login()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers" id="id88">trackers() replace_trackers()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id89">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#use-interface" id="id90">use_interface()</a></li>
<li><a class="reference internal" href="#info-hash" id="id91">info_hash()</a></li>
<li><a class="reference internal" href="#id5" id="id92">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id93">write_resume_data()</a></li>
<li><a class="reference internal" href="#id6" id="id94">status()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id95">get_download_queue()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id96">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id97">get_torrent_info()</a></li>
<li><a class="reference internal" href="#is-valid" id="id98">is_valid()</a></li>
<li><a class="reference internal" href="#torrent-handle" id="id69">torrent_handle</a><ul>
<li><a class="reference internal" href="#piece-priority-prioritize-pieces-piece-priorities-prioritize-files" id="id70">piece_priority() prioritize_pieces() piece_priorities() prioritize_files()</a></li>
<li><a class="reference internal" href="#file-progress" id="id71">file_progress()</a></li>
<li><a class="reference internal" href="#save-path" id="id72">save_path()</a></li>
<li><a class="reference internal" href="#move-storage" id="id73">move_storage()</a></li>
<li><a class="reference internal" href="#force-reannounce" id="id74">force_reannounce()</a></li>
<li><a class="reference internal" href="#scrape-tracker" id="id75">scrape_tracker()</a></li>
<li><a class="reference internal" href="#connect-peer" id="id76">connect_peer()</a></li>
<li><a class="reference internal" href="#name" id="id77">name()</a></li>
<li><a class="reference internal" href="#set-ratio" id="id78">set_ratio()</a></li>
<li><a class="reference internal" href="#set-upload-limit-set-download-limit-upload-limit-download-limit" id="id79">set_upload_limit() set_download_limit() upload_limit() download_limit()</a></li>
<li><a class="reference internal" href="#set-sequential-download" id="id80">set_sequential_download()</a></li>
<li><a class="reference internal" href="#set-peer-upload-limit-set-peer-download-limit" id="id81">set_peer_upload_limit() set_peer_download_limit()</a></li>
<li><a class="reference internal" href="#pause-resume-is-paused" id="id82">pause() resume() is_paused()</a></li>
<li><a class="reference internal" href="#resolve-countries" id="id83">resolve_countries()</a></li>
<li><a class="reference internal" href="#is-seed" id="id84">is_seed()</a></li>
<li><a class="reference internal" href="#has-metadata" id="id85">has_metadata()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id86">set_tracker_login()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers" id="id87">trackers() replace_trackers()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id88">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#use-interface" id="id89">use_interface()</a></li>
<li><a class="reference internal" href="#info-hash" id="id90">info_hash()</a></li>
<li><a class="reference internal" href="#id5" id="id91">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference internal" href="#save-resume-data" id="id92">save_resume_data()</a></li>
<li><a class="reference internal" href="#id6" id="id93">status()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id94">get_download_queue()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id95">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id96">get_torrent_info()</a></li>
<li><a class="reference internal" href="#is-valid" id="id97">is_valid()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-status" id="id99">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id100">peer_info</a></li>
<li><a class="reference internal" href="#session-settings" id="id101">session_settings</a></li>
<li><a class="reference internal" href="#pe-settings" id="id102">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id103">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id104">ip_filter</a><ul>
<li><a class="reference internal" href="#id9" id="id105">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id106">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id107">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id108">export_filter()</a></li>
<li><a class="reference internal" href="#torrent-status" id="id98">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id99">peer_info</a></li>
<li><a class="reference internal" href="#session-settings" id="id100">session_settings</a></li>
<li><a class="reference internal" href="#pe-settings" id="id101">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id102">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id103">ip_filter</a><ul>
<li><a class="reference internal" href="#id9" id="id104">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id105">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id106">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id107">export_filter()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#big-number" id="id109">big_number</a></li>
<li><a class="reference internal" href="#hasher" id="id110">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id111">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id112">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id113">add_mapping</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id114">delete_mapping</a></li>
<li><a class="reference internal" href="#router-model" id="id115">router_model()</a></li>
<li><a class="reference internal" href="#big-number" id="id108">big_number</a></li>
<li><a class="reference internal" href="#hasher" id="id109">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id110">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id111">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id112">add_mapping</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id113">delete_mapping</a></li>
<li><a class="reference internal" href="#router-model" id="id114">router_model()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#free-functions" id="id116">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id117">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id118">client_fingerprint()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id119">bdecode() bencode()</a></li>
<li><a class="reference internal" href="#free-functions" id="id115">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id116">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id117">client_fingerprint()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id118">bdecode() bencode()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#alerts" id="id120">alerts</a><ul>
<li><a class="reference internal" href="#external-ip-alert" id="id121">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id122">listen_failed_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id123">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id124">portmap_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id125">file_error_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id126">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-alert" id="id127">tracker_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id128">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id129">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id130">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id131">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id132">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id133">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id134">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id135">peer_error_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id136">invalid_request_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id137">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id138">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id139">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id140">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id141">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id142">storage_moved_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id143">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#alerts" id="id119">alerts</a><ul>
<li><a class="reference internal" href="#external-ip-alert" id="id120">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id121">listen_failed_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id122">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id123">portmap_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id124">file_error_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id125">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-alert" id="id126">tracker_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id127">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id128">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id129">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id130">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id131">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id132">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id133">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id134">peer_error_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id135">invalid_request_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id136">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id137">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id138">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id139">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id140">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id141">storage_moved_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id142">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-alert" id="id143">save_resume_data_alert</a></li>
<li><a class="reference internal" href="#dispatcher" id="id144">dispatcher</a></li>
</ul>
</li>
@ -181,7 +182,7 @@
<li><a class="reference internal" href="#write" id="id154">write()</a></li>
<li><a class="reference internal" href="#id11" id="id155">move_storage()</a></li>
<li><a class="reference internal" href="#verify-resume-data" id="id156">verify_resume_data()</a></li>
<li><a class="reference internal" href="#id12" id="id157">write_resume_data( )</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id157">write_resume_data()</a></li>
<li><a class="reference internal" href="#move-slot" id="id158">move_slot()</a></li>
<li><a class="reference internal" href="#swap-slots" id="id159">swap_slots()</a></li>
<li><a class="reference internal" href="#swap-slots3" id="id160">swap_slots3()</a></li>
@ -233,7 +234,7 @@ the <tt class="docutils literal"><span class="pre">session</span></tt>, it conta
</blockquote>
</li>
<li><p class="first">save resume data for all torrent_handles (optional, see
<a class="reference internal" href="#write-resume-data">write_resume_data()</a>)</p>
<a class="reference internal" href="#save-resume-data">save_resume_data()</a>)</p>
</li>
<li><p class="first">destruct session object</p>
</li>
@ -466,7 +467,7 @@ for checking, being checked or downloading) <tt class="docutils literal"><span c
<a class="reference internal" href="#duplicate-torrent">duplicate_torrent</a> which derives from <tt class="docutils literal"><span class="pre">std::exception</span></tt>.</p>
<p>The optional parameter, <tt class="docutils literal"><span class="pre">resume_data</span></tt> can be given if up to date fast-resume data
is available. The fast-resume data can be acquired from a running torrent by calling
<tt class="docutils literal"><span class="pre">torrent_handle::write_resume_data()</span></tt>. See <a class="reference internal" href="#fast-resume">fast resume</a>.</p>
<a class="reference internal" href="#save-resume-data">save_resume_data()</a> on <a class="reference internal" href="#torrent-handle">torrent_handle</a>. See <a class="reference internal" href="#fast-resume">fast resume</a>.</p>
<p>The <tt class="docutils literal"><span class="pre">storage_mode</span></tt> parameter refers to the layout of the storage for this torrent.
There are 3 different modes:</p>
<dl class="docutils">
@ -1627,7 +1628,7 @@ struct torrent_handle
std::string name() const;
entry write_resume_data() const;
void save_resume_data() const;
void force_reannounce() const;
void force_reannounce(boost::posix_time::time_duration) const;
void scrape_tracker() const;
@ -2024,16 +2025,18 @@ connections are used up, incoming connections may be refused or poor connections
This must be at least 2. The default is unlimited number of connections. If -1 is given to the
function, it means unlimited.</p>
</div>
<div class="section" id="write-resume-data">
<h2>write_resume_data()</h2>
<div class="section" id="save-resume-data">
<h2>save_resume_data()</h2>
<blockquote>
<pre class="literal-block">
entry write_resume_data() const;
void save_resume_data() const;
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">write_resume_data()</span></tt> generates fast-resume data and returns it as an <a class="reference internal" href="#entry">entry</a>. This <a class="reference internal" href="#entry">entry</a>
<p><tt class="docutils literal"><span class="pre">save_resume_data()</span></tt> generates fast-resume data and returns it as an <a class="reference internal" href="#entry">entry</a>. This <a class="reference internal" href="#entry">entry</a>
is suitable for being bencoded. For more information about how fast-resume works, see <a class="reference internal" href="#fast-resume">fast resume</a>.</p>
<p>There are three cases where this function will just return an empty <tt class="docutils literal"><span class="pre">entry</span></tt>:</p>
<p>This operation is asynchronous, <tt class="docutils literal"><span class="pre">save_resume_data</span></tt> will return immediately. The resume data
is delivered when it's done through an <a class="reference internal" href="#save-resume-data-alert">save_resume_data_alert</a>.</p>
<p>The fast resume data will be empty in the following cases:</p>
<blockquote>
<ol class="arabic simple">
<li>The torrent handle is invalid.</li>
@ -2043,20 +2046,59 @@ not be ready to write resume data.</li>
(see libtorrent's <a class="reference internal" href="#metadata-from-peers">metadata from peers</a> extension)</li>
</ol>
</blockquote>
<p>Note that by the time this function returns, the resume data may already be invalid if the torrent
<p>Note that by the time you receive the fast resume data, it may already be invalid if the torrent
is still downloading! The recommended practice is to first pause the torrent, then generate the
fast resume data, and then close it down. Since the disk IO is done in a separate thread, in order
to synchronize, you shoule to wait for the <tt class="docutils literal"><span class="pre">torrent_paused_alert</span></tt> before you write the resume
data.</p>
fast resume data, and then close it down. Make sure to not <a class="reference internal" href="#remove-torrent">remove_torrent()</a> before you receive
the <a class="reference internal" href="#save-resume-data-alert">save_resume_data_alert</a> though. Only pause the torrent before you save the resume data
if you will remove the torrent afterwards. There's no need to pause when saving intermittent
resume data.</p>
<p>In full allocation mode the reume data is never invalidated by subsequent
writes to the files, since pieces won't move around. This means that you don't need to
pause before writing resume data in full or sparse mode. If you don't, however, any data written to
disk after you saved resume data and before the session closed is lost.</p>
disk after you saved resume data and before the <a class="reference internal" href="#session">session</a> closed is lost.</p>
<p>It also means that if the resume data is out dated, libtorrent will not re-check the files, but assume
that it is fairly recent. The assumption is that it's better to loose a little bit than to re-check
the entire file.</p>
<p>It is still a good idea to save resume data periodically during download as well as when
closing down.</p>
<p>Example code to pause and save resume data for all torrents and wait for the alerts:</p>
<pre class="literal-block">
int num_resume_data = 0;
std::vector&lt;torrent_handle&gt; handles = ses.get_torrents();
for (std::vector&lt;torrent_handle&gt;::iterator i = handles.begin();
i != handles.end(); ++i)
{
torrent_handle&amp; h = *i;
if (!h.has_metadata()) continue;
h.pause();
h.save_resume_data();
++num_resume_data;
}
while (num_resume_data &gt; 0)
{
alert const* a = ses.wait_for_alert(seconds(10));
// if we don't get an alert within 10 seconds, abort
if (a == 0) break;
std::auto_ptr&lt;alert&gt; holder = ses.pop_alert();
save_resume_data_alert const* rd = dynamic_cast&lt;save_resume_data_alert const*&gt;(a);
if (rd == 0)
{
process_alert(a);
continue;
}
torrent_handle h = rd-&gt;handle;
boost::filesystem::ofstream out(h.save_path()
/ (h.get_torrent_info().name() + &quot;.fastresume&quot;), std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator&lt;char&gt;(out), *rd-&gt;resume_data);
--num_resume_data;
}
</pre>
</div>
<div class="section" id="id6">
<h2>status()</h2>
@ -3866,6 +3908,22 @@ struct torrent_paused_alert: torrent_alert
};
</pre>
</div>
<div class="section" id="save-resume-data-alert">
<h2>save_resume_data_alert</h2>
<p>This alert is generated as a response to a <tt class="docutils literal"><span class="pre">torrent_handle::save_resume_data</span></tt> request.
It is generated once the disk IO thread is done writing the state for this torrent.
The <tt class="docutils literal"><span class="pre">resume_data</span></tt> member points to the resume data or is 0 on errors.</p>
<pre class="literal-block">
struct save_resume_data_alert: torrent_alert
{
save_resume_alert(torrent_handle const&amp; h, std::string const&amp; msg);
boost::shared_ptr&lt;entry&gt; resume_data;
virtual std::auto_ptr&lt;alert&gt; clone() const;
};
</pre>
</div>
<div class="section" id="dispatcher">
<h2>dispatcher</h2>
<p>The <tt class="docutils literal"><span class="pre">handle_alert</span></tt> class is defined in <tt class="docutils literal"><span class="pre">&lt;libtorrent/alert.hpp&gt;</span></tt>.</p>
@ -4051,8 +4109,8 @@ on disk. If the resume data seems to be up-to-date, return true. If
not, set <tt class="docutils literal"><span class="pre">error</span></tt> to a description of what mismatched and return false.</p>
<p>The default storage may compare file sizes and time stamps of the files.</p>
</div>
<div class="section" id="id12">
<h2>write_resume_data( )</h2>
<div class="section" id="write-resume-data">
<h2>write_resume_data()</h2>
<blockquote>
<pre class="literal-block">
void write_resume_data(entry&amp; rd) const = 0;
@ -4145,7 +4203,7 @@ void delete_files() = 0;
<h1>fast resume</h1>
<p>The fast resume mechanism is a way to remember which pieces are downloaded
and where they are put between sessions. You can generate fast resume data by
calling <tt class="docutils literal"><span class="pre">torrent_handle::write_resume_data()</span></tt> on <a class="reference internal" href="#torrent-handle">torrent_handle</a>. You can
calling <a class="reference internal" href="#save-resume-data">save_resume_data()</a> on <a class="reference internal" href="#torrent-handle">torrent_handle</a>. You can
then save this data to disk and use it when resuming the torrent. libtorrent
will not check the piece hashes then, and rely on the information given in the
fast-resume data. The fast-resume data also contains information about which
@ -4180,6 +4238,10 @@ is the number of blocks per (normal sized) piece. Usually
each block is 16 * 1024 bytes in size. But if piece size is
greater than 4 megabytes, the block size will increase.</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">pieces</span></tt></td>
<td>A string with piece flags, one character per piece.
Bit 1 means we have that piece.</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">slots</span></tt></td>
<td><p class="first">list of integers. The list maps slots to piece indices. It
tells which piece is on which slot. If piece index is -2 it

View File

@ -28,7 +28,7 @@ The basic usage is as follows:
* add and remove torrents from the session at run-time
* save resume data for all torrent_handles (optional, see
`write_resume_data()`_)
`save_resume_data()`_)
* destruct session object
Each class and function is described in this manual.
@ -272,7 +272,7 @@ duplicate_torrent_ which derives from ``std::exception``.
The optional parameter, ``resume_data`` can be given if up to date fast-resume data
is available. The fast-resume data can be acquired from a running torrent by calling
``torrent_handle::write_resume_data()``. See `fast resume`_.
`save_resume_data()`_ on `torrent_handle`_. See `fast resume`_.
The ``storage_mode`` parameter refers to the layout of the storage for this torrent.
There are 3 different modes:
@ -1573,7 +1573,7 @@ Its declaration looks like this::
std::string name() const;
entry write_resume_data() const;
void save_resume_data() const;
void force_reannounce() const;
void force_reannounce(boost::posix_time::time_duration) const;
void scrape_tracker() const;
@ -1992,17 +1992,20 @@ This must be at least 2. The default is unlimited number of connections. If -1 i
function, it means unlimited.
write_resume_data()
-------------------
save_resume_data()
------------------
::
entry write_resume_data() const;
void save_resume_data() const;
``write_resume_data()`` generates fast-resume data and returns it as an entry_. This entry_
``save_resume_data()`` generates fast-resume data and returns it as an entry_. This entry_
is suitable for being bencoded. For more information about how fast-resume works, see `fast resume`_.
There are three cases where this function will just return an empty ``entry``:
This operation is asynchronous, ``save_resume_data`` will return immediately. The resume data
is delivered when it's done through an `save_resume_data_alert`_.
The fast resume data will be empty in the following cases:
1. The torrent handle is invalid.
2. The torrent is checking (or is queued for checking) its storage, it will obviously
@ -2010,16 +2013,17 @@ There are three cases where this function will just return an empty ``entry``:
3. The torrent hasn't received valid metadata and was started without metadata
(see libtorrent's `metadata from peers`_ extension)
Note that by the time this function returns, the resume data may already be invalid if the torrent
Note that by the time you receive the fast resume data, it may already be invalid if the torrent
is still downloading! The recommended practice is to first pause the torrent, then generate the
fast resume data, and then close it down. Since the disk IO is done in a separate thread, in order
to synchronize, you shoule to wait for the ``torrent_paused_alert`` before you write the resume
data.
fast resume data, and then close it down. Make sure to not `remove_torrent()`_ before you receive
the `save_resume_data_alert`_ though. Only pause the torrent before you save the resume data
if you will remove the torrent afterwards. There's no need to pause when saving intermittent
resume data.
In full allocation mode the reume data is never invalidated by subsequent
writes to the files, since pieces won't move around. This means that you don't need to
pause before writing resume data in full or sparse mode. If you don't, however, any data written to
disk after you saved resume data and before the session closed is lost.
disk after you saved resume data and before the session_ closed is lost.
It also means that if the resume data is out dated, libtorrent will not re-check the files, but assume
that it is fairly recent. The assumption is that it's better to loose a little bit than to re-check
@ -2028,6 +2032,45 @@ the entire file.
It is still a good idea to save resume data periodically during download as well as when
closing down.
Example code to pause and save resume data for all torrents and wait for the alerts::
int num_resume_data = 0;
std::vector<torrent_handle> handles = ses.get_torrents();
for (std::vector<torrent_handle>::iterator i = handles.begin();
i != handles.end(); ++i)
{
torrent_handle& h = *i;
if (!h.has_metadata()) continue;
h.pause();
h.save_resume_data();
++num_resume_data;
}
while (num_resume_data > 0)
{
alert const* a = ses.wait_for_alert(seconds(10));
// if we don't get an alert within 10 seconds, abort
if (a == 0) break;
std::auto_ptr<alert> holder = ses.pop_alert();
save_resume_data_alert const* rd = dynamic_cast<save_resume_data_alert const*>(a);
if (rd == 0)
{
process_alert(a);
continue;
}
torrent_handle h = rd->handle;
boost::filesystem::ofstream out(h.save_path()
/ (h.get_torrent_info().name() + ".fastresume"), std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), *rd->resume_data);
--num_resume_data;
}
status()
--------
@ -4019,6 +4062,24 @@ This is useful for synchronizing with the disk.
virtual std::auto_ptr<alert> clone() const;
};
save_resume_data_alert
----------------------
This alert is generated as a response to a ``torrent_handle::save_resume_data`` request.
It is generated once the disk IO thread is done writing the state for this torrent.
The ``resume_data`` member points to the resume data or is 0 on errors.
::
struct save_resume_data_alert: torrent_alert
{
save_resume_alert(torrent_handle const& h, std::string const& msg);
boost::shared_ptr<entry> resume_data;
virtual std::auto_ptr<alert> clone() const;
};
dispatcher
----------
@ -4235,8 +4296,8 @@ not, set ``error`` to a description of what mismatched and return false.
The default storage may compare file sizes and time stamps of the files.
write_resume_data( )
--------------------
write_resume_data()
-------------------
::
@ -4340,7 +4401,7 @@ fast resume
The fast resume mechanism is a way to remember which pieces are downloaded
and where they are put between sessions. You can generate fast resume data by
calling ``torrent_handle::write_resume_data()`` on torrent_handle_. You can
calling `save_resume_data()`_ on torrent_handle_. You can
then save this data to disk and use it when resuming the torrent. libtorrent
will not check the piece hashes then, and rely on the information given in the
fast-resume data. The fast-resume data also contains information about which
@ -4374,6 +4435,9 @@ The file format is a bencoded dictionary containing the following fields:
| | greater than 4 megabytes, the block size will increase. |
| | |
+----------------------+--------------------------------------------------------------+
| ``pieces`` | A string with piece flags, one character per piece. |
| | Bit 1 means we have that piece. |
+----------------------+--------------------------------------------------------------+
| ``slots`` | list of integers. The list maps slots to piece indices. It |
| | tells which piece is on which slot. If piece index is -2 it |
| | means it is free, that there's no piece there. If it is -1, |

View File

@ -596,16 +596,10 @@ void scan_dir(path const& dir_path
}
h.pause();
if (h.has_metadata())
{
entry data = h.write_resume_data();
std::stringstream s;
s << h.get_torrent_info().name() << ".fastresume";
boost::filesystem::ofstream out(h.save_path() / s.str(), std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), data);
}
ses.remove_torrent(h);
// the alert handler for save_resume_data_alert
// will save it to disk and remove the torrent
h.save_resume_data();
handles.erase(i++);
}
}
@ -988,21 +982,49 @@ int main(int ac, char* av[])
{
if (c == 'q')
{
// keep track of the number of resume data
// alerts to wait for
int num_resume_data = 0;
for (handles_t::iterator i = handles.begin();
i != handles.end(); ++i)
{
torrent_handle& h = i->second;
if (!h.is_valid() || !h.has_metadata()) continue;
// pause
std::cout << "pausing " << h.name() << std::endl;
h.pause();
// save_resume_data will generate an alert when it's done
h.save_resume_data();
++num_resume_data;
}
std::cout << "waiting for resume data" << std::endl;
entry data = h.write_resume_data();
std::stringstream s;
s << h.get_torrent_info().name() << ".fastresume";
boost::filesystem::ofstream out(h.save_path() / s.str(), std::ios_base::binary);
while (num_resume_data > 0)
{
alert const* a = ses.wait_for_alert(seconds(10));
if (a == 0)
{
std::cout << " aborting with " << num_resume_data << " outstanding "
"torrents to save resume data for" << std::endl;
break;
}
std::auto_ptr<alert> holder = ses.pop_alert();
save_resume_data_alert const* rd = dynamic_cast<save_resume_data_alert const*>(a);
if (rd == 0)
{
std::cout << a->msg() << std::endl;
continue;
}
torrent_handle h = rd->handle;
boost::filesystem::ofstream out(h.save_path()
/ (h.get_torrent_info().name() + ".fastresume"), std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), data);
ses.remove_torrent(h);
bencode(std::ostream_iterator<char>(out), *rd->resume_data);
std::cout << "fast resume data saved for " << h.name() << std::endl;
--num_resume_data;
}
break;
}
@ -1085,15 +1107,9 @@ int main(int ac, char* av[])
// write resume data for the finished torrent
torrent_handle h = p->handle;
entry data = h.write_resume_data();
std::stringstream s;
s << h.get_torrent_info().name() << ".fastresume";
boost::filesystem::ofstream out(h.save_path() / s.str(), std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), data);
h.save_resume_data();
event_string << p->handle.get_torrent_info().name() << ": "
<< a->msg();
event_string << h.name() << ": " << a->msg();
}
else if (peer_error_alert* p = dynamic_cast<peer_error_alert*>(a.get()))
{
@ -1119,6 +1135,18 @@ int main(int ac, char* av[])
{
event_string << "(" << p->ip << ") " << p->msg();
}
else if (save_resume_data_alert* p = dynamic_cast<save_resume_data_alert*>(a.get()))
{
torrent_handle h = p->handle;
if (p->resume_data)
{
boost::filesystem::ofstream out(h.save_path() / (h.name() + ".fastresume"), std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), *p->resume_data);
if (h.is_paused()) ses.remove_torrent(h);
}
event_string << "(" << h.name() << ") " << p->msg();
}
else if (torrent_alert* p = dynamic_cast<torrent_alert*>(a.get()))
{
std::string name;
@ -1356,6 +1384,7 @@ int main(int ac, char* av[])
}
}
std::cout << "saving session state" << std::endl;
{
entry session_state = ses.state();
boost::filesystem::ofstream out(".ses_state"
@ -1365,12 +1394,14 @@ int main(int ac, char* av[])
}
#ifndef TORRENT_DISABLE_DHT
std::cout << "saving DHT state" << std::endl;
dht_state = ses.dht_state();
boost::filesystem::ofstream out(".dht_state"
, std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), dht_state);
#endif
std::cout << "closing session" << std::endl;
}
catch (std::exception& e)
{

View File

@ -291,6 +291,20 @@ namespace libtorrent
{ return std::auto_ptr<alert>(new torrent_deleted_alert(*this)); }
};
struct TORRENT_EXPORT save_resume_data_alert: torrent_alert
{
save_resume_data_alert(boost::shared_ptr<entry> const& rd
, torrent_handle const& h, std::string const& msg)
: torrent_alert(h, alert::warning, msg)
, resume_data(rd)
{}
boost::shared_ptr<entry> resume_data;
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new save_resume_data_alert(*this)); }
};
struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
{
torrent_paused_alert(torrent_handle const& h, std::string const& msg)

View File

@ -81,6 +81,7 @@ namespace libtorrent
, delete_files
, check_fastresume
, check_files
, save_resume_data
};
action_t action;
@ -104,6 +105,8 @@ namespace libtorrent
// with lower priority
int priority;
boost::shared_ptr<entry> resume_data;
// this is called when operation completes
boost::function<void(int, disk_io_job const&)> callback;
};

View File

@ -212,7 +212,7 @@ namespace libtorrent
torrent_info const* info() const { return m_info.get(); }
void write_resume_data(entry& rd, std::vector<bool> const& have) const;
void write_resume_data(entry& rd) const;
void async_check_fastresume(entry const* resume_data
, boost::function<void(int, disk_io_job const&)> const& handler);
@ -242,6 +242,9 @@ namespace libtorrent
void async_move_storage(fs::path const& p
, boost::function<void(int, disk_io_job const&)> const& handler);
void async_save_resume_data(
boost::function<void(int, disk_io_job const&)> const& handler);
enum return_t
{
// return values from check_fastresume and check_files

View File

@ -178,6 +178,7 @@ namespace libtorrent
void pause();
void resume();
bool is_paused() const { return m_paused; }
void save_resume_data();
void delete_files();
@ -516,6 +517,8 @@ namespace libtorrent
torrent_handle get_handle();
void write_resume_data(entry& rd) const;
// LOGGING
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
virtual void debug_log(const std::string& line);
@ -563,6 +566,7 @@ namespace libtorrent
void on_files_released(int ret, disk_io_job const& j);
void on_torrent_paused(int ret, disk_io_job const& j);
void on_storage_moved(int ret, disk_io_job const& j);
void on_save_resume_data(int ret, disk_io_job const& j);
void on_piece_verified(int ret, disk_io_job const& j
, boost::function<void(int)> f);

View File

@ -315,6 +315,7 @@ namespace libtorrent
bool is_paused() const;
void pause() const;
void resume() const;
void save_resume_data() const;
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
void resolve_countries(bool r);
@ -354,7 +355,9 @@ namespace libtorrent
// to.
void use_interface(const char* net_interface) const;
entry write_resume_data() const;
// use save_resume_data() instead. It is async. and
// will return the resume data in an alert
entry write_resume_data() const TORRENT_DEPRECATED;
// forces this torrent to reannounce
// (make a rerequest from the tracker)

View File

@ -773,13 +773,13 @@ namespace libtorrent
std::string const& error_string = j.storage->error();
if (!error_string.empty())
{
#ifndef NDEBUG
std::cout << "ERROR: '" << error_string << "' " << j.error_file << std::endl;
#endif
j.str = error_string;
j.error_file = j.storage->error_file();
j.storage->clear_error();
ret = -1;
#ifndef NDEBUG
std::cout << "ERROR: " << error_string << " " << j.error_file << std::endl;
#endif
}
else
{
@ -1042,6 +1042,16 @@ namespace libtorrent
}
break;
}
case disk_io_job::save_resume_data:
{
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " save resume data" << std::endl;
#endif
j.resume_data.reset(new entry(entry::dictionary_t));
j.storage->write_resume_data(*j.resume_data);
ret = 0;
break;
}
}
}
#ifndef BOOST_NO_EXCEPTIONS

View File

@ -559,11 +559,8 @@ namespace libtorrent
bool storage::write_resume_data(entry& rd) const
{
if (rd.type() != entry::dictionary_t)
{
set_error("", "invalid fastresume file");
return true;
}
TORRENT_ASSERT(rd.type() == entry::dictionary_t);
std::vector<std::pair<size_type, std::time_t> > file_sizes
= get_filesizes(*m_info, m_save_path);
@ -583,7 +580,7 @@ namespace libtorrent
{
if (rd.type() != entry::dictionary_t)
{
error = "invalid fastresume file";
error = "invalid fastresume file (not a dictionary)";
return true;
}
@ -1146,6 +1143,15 @@ namespace libtorrent
{
}
void piece_manager::async_save_resume_data(
boost::function<void(int, disk_io_job const&)> const& handler)
{
disk_io_job j;
j.storage = this;
j.action = disk_io_job::save_resume_data;
m_io_thread.add_job(j, handler);
}
void piece_manager::async_release_files(
boost::function<void(int, disk_io_job const&)> const& handler)
{
@ -1280,8 +1286,7 @@ namespace libtorrent
return false;
}
void piece_manager::write_resume_data(entry& rd
, std::vector<bool> const& have) const
void piece_manager::write_resume_data(entry& rd) const
{
boost::recursive_mutex::scoped_lock lock(m_mutex);
@ -1289,9 +1294,9 @@ namespace libtorrent
m_storage->write_resume_data(rd);
entry::list_type& slots = rd["slots"].list();
if (m_storage_mode == storage_mode_compact)
{
entry::list_type& slots = rd["slots"].list();
slots.clear();
std::vector<int>::const_reverse_iterator last;
for (last = m_slot_to_piece.rbegin();
@ -1307,13 +1312,6 @@ namespace libtorrent
slots.push_back((*i >= 0) ? *i : unassigned);
}
}
else
{
for (int i = 0; i < m_info->num_pieces(); ++i)
{
slots.push_back(have[i] ? i : unassigned);
}
}
}
void piece_manager::mark_failed(int piece_index)
@ -1710,116 +1708,122 @@ namespace libtorrent
&& allocation->string() != "compact")
storage_mode = storage_mode_sparse;
// read piece map
entry const* slots = rd.find_key("slots");
if (slots == 0 || slots->type() != entry::list_t)
{
error = "missing slot list";
return check_no_fastresume(error);
}
if ((int)slots->list().size() > m_info->num_pieces())
{
error = "file has more slots than torrent (slots: "
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: "
+ boost::lexical_cast<std::string>(m_info->num_pieces()) + " )";
return check_no_fastresume(error);
}
// assume no piece is out of place (i.e. in a slot
// other than the one it should be in)
bool out_of_place = false;
if (storage_mode == storage_mode_compact)
// if we don't have a piece map, we need the slots
// if we're in compact mode, we also need the slots map
if (storage_mode == storage_mode_compact || rd.find_key("pieces") == 0)
{
int num_pieces = int(m_info->num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot);
int slot = 0;
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
// read slots map
entry const* slots = rd.find_key("slots");
if (slots == 0 || slots->type() != entry::list_t)
{
if (i->type() != entry::int_t)
error = "missing slot list";
return check_no_fastresume(error);
}
if ((int)slots->list().size() > m_info->num_pieces())
{
error = "file has more slots than torrent (slots: "
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: "
+ boost::lexical_cast<std::string>(m_info->num_pieces()) + " )";
return check_no_fastresume(error);
}
if (storage_mode == storage_mode_compact)
{
int num_pieces = int(m_info->num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot);
int slot = 0;
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
{
error = "invalid entry type in slot list";
return check_no_fastresume(error);
}
int index = int(i->integer());
if (index >= num_pieces || index < -2)
{
error = "too high index number in slot map (index: "
+ boost::lexical_cast<std::string>(index) + " size: "
+ boost::lexical_cast<std::string>(num_pieces) + ")";
return check_no_fastresume(error);
}
if (index >= 0)
{
m_slot_to_piece[slot] = index;
m_piece_to_slot[index] = slot;
if (slot != index) out_of_place = true;
}
else if (index == unassigned)
{
if (m_storage_mode == storage_mode_compact)
m_free_slots.push_back(slot);
}
else
{
TORRENT_ASSERT(index == unallocated);
if (m_storage_mode == storage_mode_compact)
m_unallocated_slots.push_back(slot);
if (i->type() != entry::int_t)
{
error = "invalid entry type in slot list";
return check_no_fastresume(error);
}
int index = int(i->integer());
if (index >= num_pieces || index < -2)
{
error = "too high index number in slot map (index: "
+ boost::lexical_cast<std::string>(index) + " size: "
+ boost::lexical_cast<std::string>(num_pieces) + ")";
return check_no_fastresume(error);
}
if (index >= 0)
{
m_slot_to_piece[slot] = index;
m_piece_to_slot[index] = slot;
if (slot != index) out_of_place = true;
}
else if (index == unassigned)
{
if (m_storage_mode == storage_mode_compact)
m_free_slots.push_back(slot);
}
else
{
TORRENT_ASSERT(index == unallocated);
if (m_storage_mode == storage_mode_compact)
m_unallocated_slots.push_back(slot);
}
}
}
}
else
{
int slot = 0;
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
else
{
if (i->type() != entry::int_t)
int slot = 0;
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
{
error = "invalid entry type in slot list";
return check_no_fastresume(error);
}
int index = int(i->integer());
if (index != slot && index >= 0)
{
error = "invalid slot index";
return check_no_fastresume(error);
if (i->type() != entry::int_t)
{
error = "invalid entry type in slot list";
return check_no_fastresume(error);
}
int index = int(i->integer());
if (index != slot && index >= 0)
{
error = "invalid slot index";
return check_no_fastresume(error);
}
}
}
}
if (!m_storage->verify_resume_data(rd, error))
return check_no_fastresume(error);
if (!m_storage->verify_resume_data(rd, error))
return check_no_fastresume(error);
// This will corrupt the storage
// use while debugging to find
// states that cannot be scanned
// by check_pieces.
// m_storage->shuffle();
// This will corrupt the storage
// use while debugging to find
// states that cannot be scanned
// by check_pieces.
// m_storage->shuffle();
if (m_storage_mode == storage_mode_compact)
{
if (m_unallocated_slots.empty()) switch_to_full_mode();
}
else
{
TORRENT_ASSERT(m_free_slots.empty());
TORRENT_ASSERT(m_unallocated_slots.empty());
if (out_of_place)
if (m_storage_mode == storage_mode_compact)
{
// in this case we're in full allocation mode, but
// we're resuming a compact allocated storage
m_state = state_expand_pieces;
m_current_slot = 0;
error = "pieces needs to be reordered";
return need_full_check;
if (m_unallocated_slots.empty()) switch_to_full_mode();
}
else
{
TORRENT_ASSERT(m_free_slots.empty());
TORRENT_ASSERT(m_unallocated_slots.empty());
if (out_of_place)
{
// in this case we're in full allocation mode, but
// we're resuming a compact allocated storage
m_state = state_expand_pieces;
m_current_slot = 0;
error = "pieces needs to be reordered";
return need_full_check;
}
}
}
return check_init_storage(error);

View File

@ -520,21 +520,18 @@ namespace libtorrent
if (!fastresume_rejected)
{
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
// parse slots
entry const* slots_ent = m_resume_data.find_key("slots");
if (slots_ent != 0 && slots_ent->type() == entry::list_t)
// parse have bitmask
entry const* pieces = m_resume_data.find_key("pieces");
if (pieces && pieces->type() == entry::string_t
&& pieces->string().length() == m_torrent_file->num_pieces())
{
entry::list_type const& slots = slots_ent->list();
for (entry::list_type::const_iterator i = slots.begin();
i != slots.end(); ++i)
std::string const& pieces_str = pieces->string();
for (int i = 0, end(pieces_str.size()); i < end; ++i)
{
if (i->type() != entry::int_t) continue;
int piece_index = int(i->integer());
if (piece_index < 0 || piece_index >= torrent_file().num_pieces())
continue;
m_have_pieces[piece_index] = true;
++m_num_pieces;
bool have = pieces_str[i] & 1;
m_have_pieces[i] = have;
m_num_pieces += have;
}
}
@ -557,10 +554,11 @@ namespace libtorrent
if (piece_index < 0 || piece_index >= torrent_file().num_pieces())
continue;
// if this assert is hit, the resume data file was corrupt
TORRENT_ASSERT(m_have_pieces[piece_index]);
m_have_pieces[piece_index] = false;
--m_num_pieces;
if (m_have_pieces[piece_index])
{
m_have_pieces[piece_index] = false;
--m_num_pieces;
}
entry const* bitmask_ent = i->find_key("bitmask");
if (bitmask_ent == 0 || bitmask_ent->type() != entry::string_t) break;
@ -1387,6 +1385,18 @@ namespace libtorrent
*/
}
void torrent::on_save_resume_data(int ret, disk_io_job const& j)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
if (alerts().should_post(alert::warning))
{
write_resume_data(*j.resume_data);
alerts().post_alert(save_resume_data_alert(j.resume_data
, get_handle(), "resume data generated"));
}
}
void torrent::on_torrent_paused(int ret, disk_io_job const& j)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -2238,6 +2248,112 @@ namespace libtorrent
}
#endif
void torrent::write_resume_data(entry& ret) const
{
ret["file-format"] = "libtorrent resume file";
ret["file-version"] = 1;
ret["allocation"] = m_storage_mode == storage_mode_sparse?"sparse"
:m_storage_mode == storage_mode_allocate?"full":"compact";
const sha1_hash& info_hash = torrent_file().info_hash();
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
// blocks per piece
int num_blocks_per_piece =
static_cast<int>(torrent_file().piece_length()) / block_size();
ret["blocks per piece"] = num_blocks_per_piece;
// if this torrent is a seed, we won't have a piece picker
// and there will be no half-finished pieces.
if (!is_seed())
{
const std::vector<piece_picker::downloading_piece>& q
= m_picker->get_download_queue();
// unfinished pieces
ret["unfinished"] = entry::list_type();
entry::list_type& up = ret["unfinished"].list();
// info for each unfinished piece
for (std::vector<piece_picker::downloading_piece>::const_iterator i
= q.begin(); i != q.end(); ++i)
{
if (i->finished == 0) continue;
entry piece_struct(entry::dictionary_t);
// the unfinished piece's index
piece_struct["piece"] = i->index;
std::string bitmask;
const int num_bitmask_bytes
= (std::max)(num_blocks_per_piece / 8, 1);
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char v = 0;
int bits = (std::min)(num_blocks_per_piece - j*8, 8);
for (int k = 0; k < bits; ++k)
v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
? (1 << k) : 0;
bitmask.insert(bitmask.end(), v);
TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
}
piece_struct["bitmask"] = bitmask;
// push the struct onto the unfinished-piece list
up.push_back(piece_struct);
}
}
// write have bitmask
entry::string_type& pieces = ret["pieces"].string();
pieces.resize(m_torrent_file->num_pieces());
for (int i = 0, end(pieces.size()); i < end; ++i)
pieces[i] = m_have_pieces[i] ? 1 : 0;
// write local peers
entry::list_type& peer_list = ret["peers"].list();
entry::list_type& banned_peer_list = ret["banned_peers"].list();
int max_failcount = m_ses.m_settings.max_failcount;
for (policy::const_iterator i = m_policy.begin_peer()
, end(m_policy.end_peer()); i != end; ++i)
{
asio::error_code ec;
if (i->second.banned)
{
tcp::endpoint ip = i->second.ip;
entry peer(entry::dictionary_t);
peer["ip"] = ip.address().to_string(ec);
if (ec) continue;
peer["port"] = ip.port();
banned_peer_list.push_back(peer);
continue;
}
// we cannot save remote connection
// since we don't know their listen port
// unless they gave us their listen port
// through the extension handshake
// so, if the peer is not connectable (i.e. we
// don't know its listen port) or if it has
// been banned, don't save it.
if (i->second.type == policy::peer::not_connectable) continue;
// don't save peers that doesn't work
if (i->second.failcount >= max_failcount) continue;
tcp::endpoint ip = i->second.ip;
entry peer(entry::dictionary_t);
peer["ip"] = ip.address().to_string(ec);
if (ec) continue;
peer["port"] = ip.port();
peer_list.push_back(peer);
}
}
void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
{
v.clear();
@ -3103,6 +3219,27 @@ namespace libtorrent
}
}
// this is an async operation triggered by the client
void torrent::save_resume_data()
{
INVARIANT_CHECK;
if (m_owning_storage.get())
{
TORRENT_ASSERT(m_storage);
m_storage->async_save_resume_data(
bind(&torrent::on_save_resume_data, shared_from_this(), _1, _2));
}
else
{
if (alerts().should_post(alert::warning))
{
alerts().post_alert(save_resume_data_alert(boost::shared_ptr<entry>()
, get_handle(), "save resume data failed, torrent is being destructed"));
}
}
}
void torrent::pause()
{
INVARIANT_CHECK;

View File

@ -253,6 +253,12 @@ namespace libtorrent
TORRENT_FORWARD(pause());
}
void torrent_handle::save_resume_data() const
{
INVARIANT_CHECK;
TORRENT_FORWARD(save_resume_data());
}
void torrent_handle::resume() const
{
INVARIANT_CHECK;
@ -431,131 +437,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
boost::shared_ptr<torrent> t = m_torrent.lock();
if (!t)
#ifdef BOOST_NO_EXCEPTIONS
return entry();
#else
throw_invalid_handle();
#endif
session_impl::mutex_t::scoped_lock l(t->session().m_mutex);
if (!t->valid_metadata())
#ifdef BOOST_NO_EXCEPTIONS
return entry();
#else
throw_invalid_handle();
#endif
std::vector<bool> have_pieces = t->pieces();
entry ret(entry::dictionary_t);
ret["file-format"] = "libtorrent resume file";
ret["file-version"] = 1;
storage_mode_t sm = t->storage_mode();
ret["allocation"] = sm == storage_mode_sparse?"sparse"
:sm == storage_mode_allocate?"full":"compact";
const sha1_hash& info_hash = t->torrent_file().info_hash();
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
// blocks per piece
int num_blocks_per_piece =
static_cast<int>(t->torrent_file().piece_length()) / t->block_size();
ret["blocks per piece"] = num_blocks_per_piece;
// if this torrent is a seed, we won't have a piece picker
// and there will be no half-finished pieces.
if (!t->is_seed())
{
const piece_picker& p = t->picker();
const std::vector<piece_picker::downloading_piece>& q
= p.get_download_queue();
// unfinished pieces
ret["unfinished"] = entry::list_type();
entry::list_type& up = ret["unfinished"].list();
// info for each unfinished piece
for (std::vector<piece_picker::downloading_piece>::const_iterator i
= q.begin(); i != q.end(); ++i)
{
if (i->finished == 0) continue;
entry piece_struct(entry::dictionary_t);
// the unfinished piece's index
piece_struct["piece"] = i->index;
have_pieces[i->index] = true;
std::string bitmask;
const int num_bitmask_bytes
= (std::max)(num_blocks_per_piece / 8, 1);
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char v = 0;
int bits = (std::min)(num_blocks_per_piece - j*8, 8);
for (int k = 0; k < bits; ++k)
v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
? (1 << k) : 0;
bitmask.insert(bitmask.end(), v);
TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
}
piece_struct["bitmask"] = bitmask;
// push the struct onto the unfinished-piece list
up.push_back(piece_struct);
}
}
std::vector<int> piece_index;
t->filesystem().write_resume_data(ret, have_pieces);
// write local peers
entry::list_type& peer_list = ret["peers"].list();
entry::list_type& banned_peer_list = ret["banned_peers"].list();
policy& pol = t->get_policy();
int max_failcount = t->settings().max_failcount;
for (policy::iterator i = pol.begin_peer()
, end(pol.end_peer()); i != end; ++i)
{
asio::error_code ec;
if (i->second.banned)
{
tcp::endpoint ip = i->second.ip;
entry peer(entry::dictionary_t);
peer["ip"] = ip.address().to_string(ec);
if (ec) continue;
peer["port"] = ip.port();
banned_peer_list.push_back(peer);
continue;
}
// we cannot save remote connection
// since we don't know their listen port
// unless they gave us their listen port
// through the extension handshake
// so, if the peer is not connectable (i.e. we
// don't know its listen port) or if it has
// been banned, don't save it.
if (i->second.type == policy::peer::not_connectable) continue;
// don't save peers that doesn't work
if (i->second.failcount >= max_failcount) continue;
tcp::endpoint ip = i->second.ip;
entry peer(entry::dictionary_t);
peer["ip"] = ip.address().to_string(ec);
if (ec) continue;
peer["port"] = ip.port();
peer_list.push_back(peer);
}
TORRENT_FORWARD(write_resume_data(ret));
t->filesystem().write_resume_data(ret);
return ret;
}