diff --git a/ChangeLog b/ChangeLog index 7692b86e9..79989d748 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,9 @@ 0.15 release + * introduced a session state save mechanism. load_state() and save_state(). + this saves all session settings and state (except torrents) + * deprecated dht_state functions and merged it with the session state * added support for multiple trackers in magnet links * added support for explicitly flushing the disk cache * added torrent priority to affect bandwidth allocation for its peers diff --git a/docs/manual.rst b/docs/manual.rst index 949207937..83169158a 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -185,9 +185,6 @@ The ``session`` class has the following synopsis:: bool load_country_db(wchar_t const* file); int as_for_ip(address const& adr); - void load_state(entry const& ses_state); - entry state() const; - void set_ip_filter(ip_filter const& f); ip_filter const& get_ip_filter() const; @@ -636,18 +633,6 @@ The ``wchar_t`` overloads are for wide character paths. .. _`MaxMind ASN database`: http://www.maxmind.com/app/asnum .. _`MaxMind GeoIP database`: http://www.maxmind.com/app/geolitecountry -load_state() state() --------------------- - - :: - - void load_state(entry const& ses_state); - entry state() const; - -These functions loads and save session state. Currently, the only state -that's stored is peak download rates for ASes. This map is used to -determine which order to connect to peers. - set_ip_filter() --------------- diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 69281857d..983d142a6 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -803,7 +803,9 @@ int main(int argc, char* argv[]) std::vector in; if (load_file(".ses_state", in) == 0) { - ses.load_state(bdecode(in.begin(), in.end())); + lazy_entry e; + if (lazy_bdecode(&in[0], &in[0] + in.size(), e) == 0) + ses.load_state(e); } #ifndef TORRENT_DISABLE_DHT @@ -816,14 +818,7 @@ int main(int argc, char* argv[]) ses.add_dht_router(std::make_pair( std::string("router.bitcomet.com"), 6881)); - if (load_file(".dht_state", in) == 0) - { - ses.start_dht(bdecode(in.begin(), in.end())); - } - else - { - ses.start_dht(); - } + ses.start_dht(); #endif ses.start_lsd(); @@ -1604,7 +1599,7 @@ int main(int argc, char* argv[]) if (a == 0) { printf(" aborting with %d outstanding " - "torrents to save resume data for", num_resume_data); + "torrents to save resume data for\n", num_resume_data); break; } @@ -1632,22 +1627,15 @@ int main(int argc, char* argv[]) save_file(combine_path(h.save_path(), h.name() + ".resume"), out); } printf("saving session state\n"); - { - entry session_state = ses.state(); + { + entry session_state; + ses.save_state(session_state); std::vector out; bencode(std::back_inserter(out), session_state); save_file(".ses_state", out); } -#ifndef TORRENT_DISABLE_DHT - printf("saving DHT state\n"); - entry dht_state = ses.dht_state(); - - std::vector out; - bencode(std::back_inserter(out), dht_state); - save_file(".dht_state", out); -#endif printf("closing session"); return 0; diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 8b89edc53..bc39c8b6f 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -195,10 +195,13 @@ namespace libtorrent void add_dht_router(std::pair const& node); void set_dht_settings(dht_settings const& s); dht_settings const& get_dht_settings() const { return m_dht_settings; } - void start_dht(entry const& startup_state); + void start_dht(); void stop_dht(); + void start_dht(entry const& startup_state); +#ifndef TORRENT_NO_DEPRECATE entry dht_state(mutex::scoped_lock& l) const; +#endif void maybe_update_udp_mapping(int nat, int local_port, int external_port); void on_dht_announce(error_code const& e); @@ -288,7 +291,7 @@ namespace libtorrent void announce_lsd(sha1_hash const& ih); - void save_state(entry& e) const; + void save_state(entry& e, mutex::scoped_lock& l) const; void load_state(lazy_entry const& e); void set_peer_proxy(proxy_settings const& s) @@ -590,6 +593,9 @@ namespace libtorrent proxy_settings m_dht_proxy; #endif +#ifndef TORRENT_DISABLE_DHT + entry m_dht_state; +#endif // set to true when the session object // is being destructed and the thread // should exit diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index 8f8eaa596..21b2bae5b 100644 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -76,6 +76,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + struct lazy_entry; struct TORRENT_EXPORT type_error: std::runtime_error { @@ -119,6 +120,7 @@ namespace libtorrent bool operator==(entry const& e) const; + void operator=(lazy_entry const&); void operator=(entry const&); void operator=(dictionary_type const&); void operator=(string_type const&); diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 0b7bec91e..1cf9b696a 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -244,10 +244,17 @@ namespace libtorrent , std::vector& ret) const; #ifndef TORRENT_DISABLE_DHT - void start_dht(entry const& startup_state = entry()); + void start_dht(); void stop_dht(); void set_dht_settings(dht_settings const& settings); - entry dht_state() const; +#ifndef TORRENT_NO_DEPRECATE + // deprecated in 0.15 + // use save_state and load_state instead + TORRENT_DEPRECATED_PREFIX + entry dht_state() const TORRENT_DEPRECATED; + TORRENT_DEPRECATED_PREFIX + void start_dht(entry const& startup_state) TORRENT_DEPRECATED; +#endif void add_dht_node(std::pair const& node); void add_dht_router(std::pair const& node); bool is_dht_running() const; @@ -272,8 +279,14 @@ namespace libtorrent #endif #endif - void load_state(entry const& ses_state); - entry state() const; +#ifndef TORRENT_NO_DEPRECATE + // deprecated in 0.15 + // use load_state and save_state instead + TORRENT_DEPRECATED_PREFIX + void load_state(entry const& ses_state) TORRENT_DEPRECATED; + TORRENT_DEPRECATED_PREFIX + entry state() const TORRENT_DEPRECATED; +#endif void set_ip_filter(ip_filter const& f); ip_filter const& get_ip_filter() const; diff --git a/src/entry.cpp b/src/entry.cpp index 7d3a65712..d18dcdff6 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/config.hpp" #include "libtorrent/escape_string.hpp" +#include "libtorrent/lazy_entry.hpp" #if defined(_MSC_VER) #define for if (false) {} else for @@ -207,6 +208,40 @@ namespace libtorrent m_type = int_t; } + // convert a lazy_entry into an old skool entry + void entry::operator=(lazy_entry const& e) + { + switch (e.type()) + { + case lazy_entry::string_t: + this->string() = e.string_value(); + break; + case lazy_entry::int_t: + this->integer() = e.int_value(); + break; + case lazy_entry::dict_t: + { + dictionary_type& d = this->dict(); + for (int i = 0; i < e.dict_size(); ++i) + { + std::pair elem = e.dict_at(i); + d[elem.first] = *elem.second; + } + break; + } + case lazy_entry::list_t: + { + list_type& l = this->list(); + for (int i = 0; i < e.list_size(); ++i) + { + l.push_back(entry()); + l.back() = *e.list_at(i); + } + break; + } + } + } + void entry::operator=(dictionary_type const& v) { destruct(); diff --git a/src/session.cpp b/src/session.cpp index 467ac1c16..75a8f26b3 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -316,7 +316,7 @@ namespace libtorrent void session::save_state(entry& e) const { mutex::scoped_lock l(m_impl->m_mutex); - m_impl->save_state(e); + m_impl->save_state(e, l); } void session::load_state(lazy_entry const& e) @@ -367,17 +367,25 @@ namespace libtorrent #endif // TORRENT_USE_WSTRING #endif // TORRENT_DISABLE_GEO_IP +#ifndef TORRENT_NO_DEPRECATE void session::load_state(entry const& ses_state) { + std::vector buf; + bencode(std::back_inserter(buf), ses_state); + lazy_entry e; + lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); mutex::scoped_lock l(m_impl->m_mutex); - m_impl->load_state(ses_state); + m_impl->load_state(e); } entry session::state() const { + entry ret; mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->state(); + m_impl->save_state(ret, l); + return ret; } +#endif void session::set_ip_filter(ip_filter const& f) { @@ -582,10 +590,11 @@ namespace libtorrent #ifndef TORRENT_DISABLE_DHT - void session::start_dht(entry const& startup_state) + void session::start_dht() { mutex::scoped_lock l(m_impl->m_mutex); - m_impl->start_dht(startup_state); + // the state is loaded in load_state() + m_impl->start_dht(); } void session::stop_dht() @@ -600,11 +609,19 @@ namespace libtorrent m_impl->set_dht_settings(settings); } +#ifndef TORRENT_NO_DEPRECATE + void session::start_dht(entry const& startup_state) + { + mutex::scoped_lock l(m_impl->m_mutex); + m_impl->start_dht(startup_state); + } + entry session::dht_state() const { mutex::scoped_lock l(m_impl->m_mutex); return m_impl->dht_state(l); } +#endif void session::add_dht_node(std::pair const& node) { diff --git a/src/session_impl.cpp b/src/session_impl.cpp index af3df593e..7ad079b0b 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -647,7 +647,7 @@ namespace aux { m_thread.reset(new thread(boost::bind(&session_impl::main_thread, this))); } - void session_impl::save_state(entry& e) const + void session_impl::save_state(entry& e, mutex::scoped_lock& l) const { save_struct(e["settings"], &m_settings, session_settings_map , sizeof(session_settings_map)/sizeof(session_settings_map[0])); @@ -656,6 +656,17 @@ namespace aux { , sizeof(dht_settings_map)/sizeof(dht_settings_map[0])); save_struct(e["dht proxy"], &m_dht_proxy, proxy_settings_map , sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0])); + + if (m_dht) + { + condition cond; + entry& state = e["dht state"]; + bool done = false; + m_io_service.post(boost::bind(&session_impl::on_dht_state_callback + , this, boost::ref(cond), boost::ref(state), boost::ref(done))); + while (!done) cond.wait(l); + } + #endif #if TORRENT_USE_I2P save_struct(e["i2p"], &i2p_proxy(), proxy_settings_map @@ -672,12 +683,27 @@ namespace aux { , sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0])); save_struct(e["tracker proxy"], &m_tracker_proxy, proxy_settings_map , sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0])); + +#ifndef TORRENT_DISABLE_GEO_IP + entry::dictionary_type& as_map = e["AS map"].dict(); + char buf[10]; + for (std::map::const_iterator i = m_as_peak.begin() + , end(m_as_peak.end()); i != end; ++i) + { + if (i->second == 0) continue; + sprintf(buf, "%05d", i->first); + as_map[buf] = i->second; + } +#endif + } void session_impl::load_state(lazy_entry const& e) { lazy_entry const* settings; + if (e.type() != lazy_entry::dict_t) return; + settings = e.dict_find_dict("settings"); if (settings) { @@ -705,6 +731,13 @@ namespace aux { , sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0])); set_dht_proxy(s); } + + settings = e.dict_find_dict("dht state"); + if (settings) + { + m_dht_state = *settings; + } + #endif #if TORRENT_USE_I2P @@ -755,6 +788,21 @@ namespace aux { , sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0])); set_tracker_proxy(s); } + +#ifndef TORRENT_DISABLE_GEO_IP + settings = e.dict_find_dict("AS map"); + if (settings) + { + for (int i = 0; i < settings->dict_size(); ++i) + { + std::pair item = settings->dict_at(i); + int as_num = atoi(item.firstc_str()); + if (item.second.type() != lazy_entry::int_t || item.second.int_value() == 0) continue; + int& peak = m_as_peak[as_num]; + if (peak < item.second.integer()) peak = item.second.integer(); + } + } +#endif } #ifndef TORRENT_DISABLE_GEO_IP @@ -843,43 +891,6 @@ namespace aux { #endif // TORRENT_DISABLE_GEO_IP - void session_impl::load_state(entry const& ses_state) - { - if (ses_state.type() != entry::dictionary_t) return; -#ifndef TORRENT_DISABLE_GEO_IP - entry const* as_map = ses_state.find_key("AS map"); - if (as_map && as_map->type() == entry::dictionary_t) - { - entry::dictionary_type const& as_peak = as_map->dict(); - for (entry::dictionary_type::const_iterator i = as_peak.begin() - , end(as_peak.end()); i != end; ++i) - { - int as_num = atoi(i->first.c_str()); - if (i->second.type() != entry::int_t || i->second.integer() == 0) continue; - int& peak = m_as_peak[as_num]; - if (peak < i->second.integer()) peak = i->second.integer(); - } - } -#endif - } - - entry session_impl::state() const - { - entry ret; -#ifndef TORRENT_DISABLE_GEO_IP - entry::dictionary_type& as_map = ret["AS map"].dict(); - char buf[10]; - for (std::map::const_iterator i = m_as_peak.begin() - , end(m_as_peak.end()); i != end; ++i) - { - if (i->second == 0) continue; - sprintf(buf, "%05d", i->first); - as_map[buf] = i->second; - } -#endif - return ret; - } - #ifndef TORRENT_DISABLE_EXTENSIONS void session_impl::add_extension( boost::function(torrent*, void*)> ext) @@ -3241,6 +3252,9 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT + void session_impl::start_dht() + { start_dht(m_dht_state); } + void session_impl::start_dht(entry const& startup_state) { INVARIANT_CHECK; @@ -3365,6 +3379,7 @@ namespace aux { c.signal(l); } +#ifndef TORRENT_NO_DEPRECATE entry session_impl::dht_state(mutex::scoped_lock& l) const { condition cond; @@ -3376,6 +3391,7 @@ namespace aux { while (!done) cond.wait(l); return e; } +#endif void session_impl::add_dht_node(std::pair const& node) {