From d2f328cc8edb82f6988a7c13c30208067af1ab6e Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 26 May 2011 03:38:45 +0000 Subject: [PATCH] * Added 'method.rlookup' and 'method.rlookup.clear' commands for looking up the event handlers holding a specified key. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1231 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_download.cc | 1 + src/command_dynamic.cc | 14 ++++++++++ src/main.cc | 28 ++++++++++---------- src/rpc/fixed_key.h | 8 ++++++ src/rpc/object_storage.cc | 56 +++++++++++++++++++++++++++++++++++++++ src/rpc/object_storage.h | 33 ++++++++++++++++++----- src/rpc/parse.cc | 6 +++++ 7 files changed, 125 insertions(+), 21 deletions(-) diff --git a/src/command_download.cc b/src/command_download.cc index 3f97d9c4..ed98c62b 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -627,6 +627,7 @@ initialize_command_download() { CMD2_DL_V ("d.pause", std::bind(&core::DownloadList::pause_default, control->core()->download_list(), std::placeholders::_1)); CMD2_DL_V ("d.open", std::bind(&core::DownloadList::open_throw, control->core()->download_list(), std::placeholders::_1)); CMD2_DL_V ("d.close", std::bind(&core::DownloadList::close_throw, control->core()->download_list(), std::placeholders::_1)); + CMD2_DL_V ("d.close.directly", std::bind(&core::DownloadList::close_directly, control->core()->download_list(), std::placeholders::_1)); CMD2_DL_V ("d.erase", std::bind(&core::DownloadList::erase_ptr, control->core()->download_list(), std::placeholders::_1)); CMD2_DL_V ("d.check_hash", std::bind(&core::DownloadList::check_hash, control->core()->download_list(), std::placeholders::_1)); diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc index 5cab378d..f3cef370 100644 --- a/src/command_dynamic.cc +++ b/src/command_dynamic.cc @@ -170,6 +170,15 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) { cmd_flags, NULL, NULL); } + // Not the right argument. + // if (flags & rpc::object_storage::flag_rlookup) { + // rpc::commands.insert_slot >::type> + // (create_new_key<9>(rawKey, ".rlookup"), + // std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), rawKey), + // &rpc::command_base_call_string, + // cmd_flags, NULL, NULL); + // } + // TODO: Next... Make test class for this. // // Ehm... no proper handling if these throw. @@ -254,6 +263,8 @@ system_method_insert(const torrent::Object::list_type& args) { new_flags |= rpc::object_storage::flag_private; if (options.find("const") != std::string::npos) new_flags |= rpc::object_storage::flag_constant; + if (options.find("rlookup") != std::string::npos) + new_flags |= rpc::object_storage::flag_rlookup; return system_method_insert_object(new_args, new_flags); @@ -431,4 +442,7 @@ initialize_command_dynamic() { CMD2_ANY_LIST ("method.has_key", std::bind(&system_method_has_key, std::placeholders::_2)); CMD2_ANY_LIST ("method.set_key", std::bind(&system_method_set_key, std::placeholders::_2)); CMD2_ANY_STRING ("method.list_keys", std::bind(&system_method_list_keys, std::placeholders::_2)); + + CMD2_ANY_STRING ("method.rlookup", std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), std::placeholders::_2)); + CMD2_ANY_STRING_V("method.rlookup.clear", std::bind(&rpc::object_storage::rlookup_clear, control->object_storage(), std::placeholders::_2)); } diff --git a/src/main.cc b/src/main.cc index dcddf958..8fbb5d37 100644 --- a/src/main.cc +++ b/src/main.cc @@ -217,21 +217,21 @@ main(int argc, char** argv) { // "method.insert.simple = test.method.simple,((print,simple_test_,$argument.0=))\n" // "method.insert.simple = test.method.double,((print,simple_test_,$argument.0=)),\"print=simple_test_,$argument.1=\"\n" - "method.insert = event.download.inserted,multi\n" - "method.insert = event.download.inserted_new,multi\n" - "method.insert = event.download.inserted_session,multi\n" - "method.insert = event.download.erased,multi\n" - "method.insert = event.download.opened,multi\n" - "method.insert = event.download.closed,multi\n" - "method.insert = event.download.resumed,multi\n" - "method.insert = event.download.paused,multi\n" + "method.insert = event.download.inserted,multi|rlookup|static\n" + "method.insert = event.download.inserted_new,multi|rlookup|static\n" + "method.insert = event.download.inserted_session,multi|rlookup|static\n" + "method.insert = event.download.erased,multi|rlookup|static\n" + "method.insert = event.download.opened,multi|rlookup|static\n" + "method.insert = event.download.closed,multi|rlookup|static\n" + "method.insert = event.download.resumed,multi|rlookup|static\n" + "method.insert = event.download.paused,multi|rlookup|static\n" - "method.insert = event.download.finished,multi\n" - "method.insert = event.download.hash_done,multi\n" - "method.insert = event.download.hash_failed,multi\n" - "method.insert = event.download.hash_final_failed,multi\n" - "method.insert = event.download.hash_removed,multi\n" - "method.insert = event.download.hash_queued,multi\n" + "method.insert = event.download.finished,multi|rlookup|static\n" + "method.insert = event.download.hash_done,multi|rlookup|static\n" + "method.insert = event.download.hash_failed,multi|rlookup|static\n" + "method.insert = event.download.hash_final_failed,multi|rlookup|static\n" + "method.insert = event.download.hash_removed,multi|rlookup|static\n" + "method.insert = event.download.hash_queued,multi|rlookup|static\n" "method.set_key = event.download.inserted, 1_connect_logs, d.initialize_logs=\n" "method.set_key = event.download.inserted_new, 1_prepare, \"branch=d.state=,view.set_visible=started,view.set_visible=stopped ;d.save_full_session=\"\n" diff --git a/src/rpc/fixed_key.h b/src/rpc/fixed_key.h index 31809b51..ebc61356 100644 --- a/src/rpc/fixed_key.h +++ b/src/rpc/fixed_key.h @@ -80,6 +80,9 @@ public: bool operator == (const fixed_key_type& rhs) const { return m_size == rhs.m_size && std::memcmp(m_data, rhs.m_data, m_size) == 0; } bool operator != (const fixed_key_type& rhs) const { return m_size != rhs.m_size || std::memcmp(m_data, rhs.m_data, m_size) != 0; } + bool operator == (const torrent::raw_string& rhs) const { return m_size == rhs.size() && std::memcmp(m_data, rhs.data(), m_size) == 0; } + bool operator != (const torrent::raw_string& rhs) const { return m_size != rhs.size() || std::memcmp(m_data, rhs.data(), m_size) != 0; } + bool operator == (const std::string& rhs) const { return m_size == rhs.size() && std::memcmp(m_data, rhs.data(), m_size) == 0; } private: @@ -110,6 +113,11 @@ struct hash_fixed_key_type { } }; +template +bool operator == (const torrent::raw_string& lhs, const fixed_key_type& rhs) { + return lhs.size() == rhs.size() && std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; +} + } #endif diff --git a/src/rpc/object_storage.cc b/src/rpc/object_storage.cc index bbba6231..a9f013e1 100644 --- a/src/rpc/object_storage.cc +++ b/src/rpc/object_storage.cc @@ -38,6 +38,7 @@ #include "object_storage.h" +#include "rak/functional.h" #include "parse.h" #include "parse_commands.h" @@ -77,6 +78,9 @@ object_storage::insert(const char* key_data, uint32_t key_size, const torrent::O if (!(flags & mask_type)) throw torrent::input_error("No type flags set when calling object_storage::insert."); + if ((flags & flag_rlookup) && (!(flags & flag_static) || !(flags & flag_multi_type))) + throw torrent::input_error("Cannot insert non-static or non-multi-type object with rlookup enabled."); + std::pair result = base_type::insert(std::make_pair(key_type(key_data, key_size), object_storage_node())); if (!result.second) @@ -183,6 +187,21 @@ object_storage::erase_multi_key(const torrent::raw_string& key, const std::strin return; itr->second.object.erase_key(cmd_key); + + if (!(itr->second.flags & flag_rlookup)) + return; + + // Remove the rlookup entry. + rlookup_iterator r_itr = m_rlookup.find(cmd_key); + + if (r_itr == m_rlookup.end()) + return; + + rlookup_mapped_iterator rm_itr = std::find_if(r_itr->second.begin(), r_itr->second.end(), + rak::equal(key, rak::mem_ptr(&value_type::first))); + + if (rm_itr != r_itr->second.end()) + r_itr->second.erase(rm_itr); } void @@ -192,7 +211,44 @@ object_storage::set_multi_key(const torrent::raw_string& key, const std::string& if (itr == end(0) || (itr->second.flags & mask_type) != flag_multi_type) throw torrent::input_error("Key not found or wrong type."); + if (itr->second.flags & flag_rlookup) { + rlookup_iterator r_itr = m_rlookup.find(cmd_key); + + if (r_itr == m_rlookup.end()) + r_itr = m_rlookup.insert(std::make_pair(cmd_key, rlookup_type::mapped_type())).first; + + if (std::find_if(r_itr->second.begin(), r_itr->second.end(), + rak::equal(key, rak::mem_ptr(&value_type::first))) == r_itr->second.end()) + r_itr->second.push_back(&*itr); + } + itr->second.object.insert_key(cmd_key, object); } +torrent::Object::list_type +object_storage::rlookup_list(const std::string& cmd_key) { + torrent::Object::list_type result; + + rlookup_iterator r_itr = m_rlookup.find(cmd_key); + + if (r_itr != m_rlookup.end()) + std::transform(r_itr->second.begin(), r_itr->second.end(), std::back_inserter(result), + std::bind(&key_type::c_str, std::bind(rak::mem_ptr(&value_type::first), std::placeholders::_1))); + + return result; +} + +void +object_storage::rlookup_clear(const std::string& cmd_key) { + rlookup_iterator r_itr = m_rlookup.find(cmd_key); + + if (r_itr == m_rlookup.end()) + return; + + for (rlookup_mapped_iterator first = r_itr->second.begin(), last = r_itr->second.end(); first != last; first++) + (*first)->second.object.erase_key(cmd_key); + + r_itr->second.clear(); +} + } diff --git a/src/rpc/object_storage.h b/src/rpc/object_storage.h index c9081c63..9c50be86 100644 --- a/src/rpc/object_storage.h +++ b/src/rpc/object_storage.h @@ -45,6 +45,7 @@ #include #include +#include "rak/unordered_vector.h" #include "command.h" #include "fixed_key.h" @@ -55,9 +56,13 @@ struct object_storage_node { char flags; }; -class object_storage : private std::unordered_map, object_storage_node, hash_fixed_key_type> { +typedef std::unordered_map, object_storage_node, hash_fixed_key_type> object_storage_base_type; + +class object_storage : private object_storage_base_type { public: - typedef std::unordered_map, object_storage_node, hash_fixed_key_type> base_type; + // Should really change rlookup_type into a set with pair values. + typedef object_storage_base_type base_type; + typedef std::map > rlookup_type; using base_type::key_type; using base_type::value_type; @@ -66,6 +71,9 @@ public: using base_type::local_iterator; using base_type::const_local_iterator; + typedef rlookup_type::iterator rlookup_iterator; + typedef rlookup_type::mapped_type::iterator rlookup_mapped_iterator; + using base_type::begin; using base_type::end; using base_type::size; @@ -76,6 +84,8 @@ public: using base_type::max_bucket_count; using base_type::load_factor; + // Verify rlookup is static / const. + using base_type::clear; using base_type::find; using base_type::erase; @@ -90,9 +100,10 @@ public: static const unsigned int mask_type = 0xf; - static const unsigned int flag_constant = 0x10; - static const unsigned int flag_static = 0x20; - static const unsigned int flag_private = 0x40; + static const unsigned int flag_constant = 0x10; + static const unsigned int flag_static = 0x20; + static const unsigned int flag_private = 0x40; + static const unsigned int flag_rlookup = 0x80; static const size_t key_size = key_type::max_size; @@ -128,8 +139,8 @@ public: const torrent::Object& set_str_list(const std::string& str, const torrent::Object::list_type& object) { return set_list(torrent::raw_string::from_string(str), object); } // Functions callers: - torrent::Object call_function(const torrent::raw_string& key, target_type target, const torrent::Object& object); - torrent::Object call_function_str(const std::string& key, target_type target, const torrent::Object& object); + torrent::Object call_function(const torrent::raw_string& key, target_type target, const torrent::Object& object); + torrent::Object call_function_str(const std::string& key, target_type target, const torrent::Object& object); // Single-command function: @@ -144,6 +155,14 @@ public: bool has_str_multi_key(const std::string& key, const std::string& cmd_key); void erase_str_multi_key(const std::string& key, const std::string& cmd_key); void set_str_multi_key(const std::string& key, const std::string& cmd_key, const std::string& object); + + torrent::Object::list_type rlookup_list(const std::string& cmd_key); + torrent::Object rlookup_obj_list(const std::string& cmd_key) { return torrent::Object::from_list(rlookup_list(cmd_key)); } + + void rlookup_clear(const std::string& cmd_key); + +private: + rlookup_type m_rlookup; }; // diff --git a/src/rpc/parse.cc b/src/rpc/parse.cc index be57d86e..e0bbfd67 100644 --- a/src/rpc/parse.cc +++ b/src/rpc/parse.cc @@ -452,6 +452,9 @@ print_object(char* first, char* last, const torrent::Object* src, int flags) { return std::min(first + snprintf(first, std::distance(first, last), "%lli", src->as_value()), last); case torrent::Object::TYPE_LIST: + if (first != last) + *first = '\0'; + for (torrent::Object::list_const_iterator itr = src->as_list().begin(), itrEnd = src->as_list().end(); itr != itrEnd; itr++) { first = print_object(first, last, &*itr, flags); @@ -462,6 +465,9 @@ print_object(char* first, char* last, const torrent::Object* src, int flags) { return first; case torrent::Object::TYPE_NONE: + if (first != last) + *first = '\0'; + return first; default: throw torrent::input_error("Invalid type.");