From bb3069170c5867152647658f7c92ed72010bcbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20D=C3=A9saulniers?= Date: Tue, 14 Jun 2016 21:40:46 -0400 Subject: [PATCH] pht: add key spec, handling maximum prefix length This commit adds the new KeySpec in the Pht constructor signature so that all keys used inside a same PHT structure have the same maximal length. --- include/opendht/indexation/pht.h | 54 ++++++++++++++------ tools/dhtnode.cpp | 84 ++++++++++++++++++++------------ 2 files changed, 93 insertions(+), 45 deletions(-) diff --git a/include/opendht/indexation/pht.h b/include/opendht/indexation/pht.h index 05ca637f..d60afbe1 100644 --- a/include/opendht/indexation/pht.h +++ b/include/opendht/indexation/pht.h @@ -142,6 +142,9 @@ struct IndexEntry : public dht::Value::Serializable { }; class Pht { + static constexpr const char* INVALID_KEY = "Key does not match the PHT key spec."; + + /* Prefixes the user_type for all dht values put on the DHT */ static constexpr const char* INDEX_PREFIX = "index.pht."; public: @@ -150,7 +153,11 @@ public: */ static constexpr const size_t MAX_NODE_ENTRY_COUNT {16}; + /* A key for a an index entry */ using Key = std::map; + /* Specifications of the keys. It defines the number, the length and the + * serialization order of fields. */ + using KeySpec = std::map; using LookupCallback = std::function>& values, Prefix p)>; typedef void (*LookupCallbackRaw)(std::vector>* values, Prefix* p, void *user_data); @@ -162,8 +169,12 @@ public: }; } - Pht(std::string name, std::shared_ptr dht) - : name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), dht_(dht) { } + Pht(std::string name, KeySpec k_spec, std::shared_ptr dht) + : name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), keySpec_(k_spec), dht_(dht) + { + if (k_spec.size() != 1) + throw std::invalid_argument("PHT only supports unidimensional data."); + } virtual ~Pht () { } /** @@ -295,19 +306,6 @@ private: std::multimap> leaves_; }; - /** - * Linearizes the key into a unidimensional key. A pht only takes - * unidimensional key. - * - * @param Key The initial key. - * - * @return return The linearized key. - */ - static Prefix linearize(Key k) { - if (k.size() != 1) { throw std::invalid_argument("PHT only supports unidimensional data."); } - return k.begin()->second; - }; - /** * Performs a step in the lookup operation. Each steps are performed * asynchronously. @@ -317,6 +315,31 @@ private: DoneCallbackSimple done_cb, std::shared_ptr max_common_prefix_len, int start = -1, bool all_values = false); + /** + * Linearizes the key into a unidimensional key. A pht only takes + * unidimensional key. + * + * @param Key The initial key. + * + * @return the prefix of the linearized key. + */ + virtual Prefix linearize(Key k) const { + if (not validKey(k)) { throw std::invalid_argument(INVALID_KEY); } + return Blob {k.begin()->second.begin(), k.begin()->second.begin() + keySpec_.begin()->second}; + }; + + /** + * Tells if the key is valid according to the key spec. + */ + bool validKey(const Key& k) const { + return k.size() == keySpec_.size() and + std::equal(k.begin(), k.end(), keySpec_.begin(), + [&](const Key::value_type& key, const KeySpec::value_type& key_spec) { + return key.first == key_spec.first; + } + ); + } + /** * Updates the canary token on the node responsible for the specified * Prefix. @@ -325,6 +348,7 @@ private: const std::string name_; const std::string canary_; + const KeySpec keySpec_; Cache cache_; std::shared_ptr dht_; }; diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index 7f5e7144..0dae65de 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -73,7 +73,7 @@ void print_help() { << std::endl; } -void cmd_loop(std::shared_ptr& dht, std::map indexes, dht_params& params) +void cmd_loop(std::shared_ptr& dht, std::map indexes, dht_params& params) { print_node_info(dht, params); std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl; @@ -161,11 +161,23 @@ void cmd_loop(std::shared_ptr& dht, std::map> index >> keystr; + auto new_index = std::find_if(indexes.begin(), indexes.end(), + [&](std::pair& i) { + return i.first == index; + }) == indexes.end(); if (not index.size()) { std::cout << "You must enter the index name." << std::endl; continue; - } else { - indexes.emplace(index, dht::indexation::Pht {index, dht}); + } else if (new_index) { + using namespace dht::indexation; + try { + auto key = createPhtKey(parseStringMap(keystr)); + Pht::KeySpec ks; + std::transform(key.begin(), key.end(), std::inserter(ks, ks.end()), [](Pht::Key::value_type& f) { + return std::make_pair(f.first, f.second.size()); + }); + indexes.emplace(index, Pht {index, std::move(ks), dht}); + } catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; } } } else { @@ -250,25 +262,30 @@ void cmd_loop(std::shared_ptr& dht, std::map> exact_match; - indexes.at(index).lookup(createPhtKey(parseStringMap(keystr)), - [=](std::vector>& vals, indexation::Prefix p) { - std::cout << "Pht::lookup: at prefix \"" << p.toString() << "\"" << ", hash is " << p.hash() << std::endl; - for (auto v : vals) { - std::cout << "Pht::lookup: found hash" << std::endl - << "\t" << v->first << "[vid: " << v->second << "]" << std::endl; - } - std::cout << "Pht::lookup: done." << std::endl; - }, - [start](bool ok) { - if (not ok) { - std::cout << "Pht::lookup: dht Get failed." << std::endl; - } + try { + auto key = createPhtKey(parseStringMap(keystr)); + std::cout << "Pht::lookup(key=\"" << indexes.at(index).linearize(key).toString() << "\")" << std::endl; + indexes.at(index).lookup(key, + [=](std::vector>& vals, indexation::Prefix p) { + if (vals.empty()) + return; + std::cout << "Pht::lookup: found entries!" << std::endl + << " prefix: \"" << p.toString() << "\"" << std::endl + << " hash: " << p.hash() << std::endl; + std::cout << " entries:" << std::endl; + for (auto v : vals) + std::cout << " " << v->first.toString() << "[vid: " << v->second << "]" << std::endl; + }, + [start](bool ok) { + auto end = std::chrono::high_resolution_clock::now(); + std::cout << "Pht::lookup: " << (ok ? "done." : "failed.") + << " took " << print_dt(end-start) << "s)" << std::endl; - auto end = std::chrono::high_resolution_clock::now(); - std::cout << "Pht::lookup: took " << print_dt(end-start) << "s)" << std::endl; - - }, exact_match.size() != 0 and exact_match == "false" ? false : true - ); + }, exact_match.size() != 0 and exact_match == "false" ? false : true + ); + } + catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; } + catch (std::out_of_range& e) { } } else if (op == "ii") { iss >> idstr; @@ -277,15 +294,22 @@ void cmd_loop(std::shared_ptr& dht, std::map(); - std::map indexes; + std::map indexes; try { auto params = parseArgs(argc, argv);