2019-01-22 01:14:02 +00:00
|
|
|
#ifndef LLARP_DHT_TXHOLDER
|
|
|
|
#define LLARP_DHT_TXHOLDER
|
|
|
|
|
|
|
|
#include <dht/tx.hpp>
|
|
|
|
#include <dht/txowner.hpp>
|
|
|
|
#include <util/time.hpp>
|
2019-02-08 19:43:25 +00:00
|
|
|
#include <util/status.hpp>
|
2019-01-22 01:14:02 +00:00
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace dht
|
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename K, typename V, typename K_Hash>
|
2019-04-19 15:10:26 +00:00
|
|
|
struct TXHolder
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
using TXPtr = std::unique_ptr<TX<K, V>>;
|
2019-01-22 01:14:02 +00:00
|
|
|
// tx who are waiting for a reply for each key
|
2020-04-07 18:38:56 +00:00
|
|
|
std::unordered_multimap<K, TXOwner, K_Hash> waiting;
|
2019-01-22 01:14:02 +00:00
|
|
|
// tx timesouts by key
|
2020-04-07 18:38:56 +00:00
|
|
|
std::unordered_map<K, llarp_time_t, K_Hash> timeouts;
|
2019-01-22 01:14:02 +00:00
|
|
|
// maps remote peer with tx to handle reply from them
|
2020-04-07 18:38:56 +00:00
|
|
|
std::unordered_map<TXOwner, TXPtr, TXOwner::Hash> tx;
|
2019-01-22 01:14:02 +00:00
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
const TX<K, V>*
|
2019-01-22 01:14:02 +00:00
|
|
|
GetPendingLookupFrom(const TXOwner& owner) const;
|
|
|
|
|
2019-02-11 17:14:43 +00:00
|
|
|
util::StatusObject
|
2019-04-19 15:10:26 +00:00
|
|
|
ExtractStatus() const
|
2019-02-08 19:43:25 +00:00
|
|
|
{
|
2019-02-11 17:14:43 +00:00
|
|
|
util::StatusObject obj{};
|
2020-04-07 18:38:56 +00:00
|
|
|
std::vector<util::StatusObject> txObjs, timeoutsObjs, waitingObjs;
|
|
|
|
std::transform(
|
|
|
|
tx.begin(),
|
|
|
|
tx.end(),
|
|
|
|
std::back_inserter(txObjs),
|
|
|
|
[](const auto& item) -> util::StatusObject {
|
|
|
|
return util::StatusObject{{"owner", item.first.ExtractStatus()},
|
|
|
|
{"tx", item.second->ExtractStatus()}};
|
|
|
|
});
|
2019-08-19 09:33:26 +00:00
|
|
|
obj["tx"] = txObjs;
|
2019-02-11 17:14:43 +00:00
|
|
|
std::transform(
|
2020-04-07 18:38:56 +00:00
|
|
|
timeouts.begin(),
|
|
|
|
timeouts.end(),
|
|
|
|
std::back_inserter(timeoutsObjs),
|
2019-02-11 17:14:43 +00:00
|
|
|
[](const auto& item) -> util::StatusObject {
|
2020-02-25 17:05:13 +00:00
|
|
|
return util::StatusObject{{"time", to_json(item.second)},
|
2020-03-01 15:59:19 +00:00
|
|
|
{"target", item.first.ExtractStatus()}};
|
2019-02-11 17:14:43 +00:00
|
|
|
});
|
2019-08-19 09:33:26 +00:00
|
|
|
obj["timeouts"] = timeoutsObjs;
|
2020-04-07 18:38:56 +00:00
|
|
|
std::transform(
|
|
|
|
waiting.begin(),
|
|
|
|
waiting.end(),
|
|
|
|
std::back_inserter(waitingObjs),
|
|
|
|
[](const auto& item) -> util::StatusObject {
|
|
|
|
return util::StatusObject{{"target", item.first.ExtractStatus()},
|
|
|
|
{"whoasked", item.second.ExtractStatus()}};
|
|
|
|
});
|
2019-08-19 09:33:26 +00:00
|
|
|
obj["waiting"] = waitingObjs;
|
2019-02-11 17:14:43 +00:00
|
|
|
return obj;
|
2019-02-08 19:43:25 +00:00
|
|
|
}
|
|
|
|
|
2019-01-22 01:14:02 +00:00
|
|
|
bool
|
|
|
|
HasLookupFor(const K& target) const
|
|
|
|
{
|
|
|
|
return timeouts.find(target) != timeouts.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
HasPendingLookupFrom(const TXOwner& owner) const
|
|
|
|
{
|
|
|
|
return GetPendingLookupFrom(owner) != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
NewTX(
|
|
|
|
const TXOwner& askpeer,
|
|
|
|
const TXOwner& whoasked,
|
|
|
|
const K& k,
|
|
|
|
TX<K, V>* t,
|
|
|
|
llarp_time_t requestTimeoutMS = 15s);
|
2019-01-22 01:14:02 +00:00
|
|
|
|
|
|
|
/// mark tx as not fond
|
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
NotFound(const TXOwner& from, const std::unique_ptr<Key_t>& next);
|
2019-01-22 01:14:02 +00:00
|
|
|
|
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
Found(const TXOwner& from, const K& k, const std::vector<V>& values)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
Inform(from, k, values, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// inform all watches for key of values found
|
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
Inform(
|
|
|
|
TXOwner from,
|
|
|
|
K key,
|
|
|
|
std::vector<V> values,
|
|
|
|
bool sendreply = false,
|
|
|
|
bool removeTimeouts = true);
|
2019-01-22 01:14:02 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
Expire(llarp_time_t now);
|
|
|
|
};
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename K, typename V, typename K_Hash>
|
|
|
|
const TX<K, V>*
|
|
|
|
TXHolder<K, V, K_Hash>::GetPendingLookupFrom(const TXOwner& owner) const
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
auto itr = tx.find(owner);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr == tx.end())
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2019-07-06 17:03:40 +00:00
|
|
|
|
|
|
|
return itr->second.get();
|
2019-01-22 01:14:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename K, typename V, typename K_Hash>
|
2019-01-22 01:14:02 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
TXHolder<K, V, K_Hash>::NewTX(
|
|
|
|
const TXOwner& askpeer,
|
|
|
|
const TXOwner& whoasked,
|
|
|
|
const K& k,
|
|
|
|
TX<K, V>* t,
|
|
|
|
llarp_time_t requestTimeoutMS)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
(void)whoasked;
|
2020-04-07 18:38:56 +00:00
|
|
|
tx.emplace(askpeer, std::unique_ptr<TX<K, V>>(t));
|
2019-01-22 01:14:02 +00:00
|
|
|
auto count = waiting.count(k);
|
|
|
|
waiting.emplace(k, askpeer);
|
|
|
|
|
|
|
|
auto itr = timeouts.find(k);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr == timeouts.end())
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
timeouts.emplace(k, time_now_ms() + requestTimeoutMS);
|
|
|
|
}
|
2020-04-07 18:38:56 +00:00
|
|
|
if (count == 0)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
t->Start(askpeer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename K, typename V, typename K_Hash>
|
2019-01-22 01:14:02 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
TXHolder<K, V, K_Hash>::NotFound(const TXOwner& from, const std::unique_ptr<Key_t>&)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
2019-03-27 12:36:27 +00:00
|
|
|
auto txitr = tx.find(from);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (txitr == tx.end())
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-01-14 00:49:09 +00:00
|
|
|
Inform(from, txitr->second->target, {}, true, true);
|
2019-01-22 01:14:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename K, typename V, typename K_Hash>
|
2019-01-22 01:14:02 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
TXHolder<K, V, K_Hash>::Inform(
|
|
|
|
TXOwner from, K key, std::vector<V> values, bool sendreply, bool removeTimeouts)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
auto range = waiting.equal_range(key);
|
2020-04-07 18:38:56 +00:00
|
|
|
auto itr = range.first;
|
|
|
|
while (itr != range.second)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
auto txitr = tx.find(itr->second);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (txitr != tx.end())
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& value : values)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
txitr->second->OnFound(from.node, value);
|
|
|
|
}
|
2020-04-07 18:38:56 +00:00
|
|
|
if (sendreply)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
txitr->second->SendReply();
|
|
|
|
tx.erase(txitr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
if (sendreply)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
waiting.erase(key);
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
if (removeTimeouts)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
timeouts.erase(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
template <typename K, typename V, typename K_Hash>
|
2019-01-22 01:14:02 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
TXHolder<K, V, K_Hash>::Expire(llarp_time_t now)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
auto itr = timeouts.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != timeouts.end())
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (now >= itr->second)
|
2019-01-22 01:14:02 +00:00
|
|
|
{
|
|
|
|
Inform(TXOwner{}, itr->first, {}, true, false);
|
|
|
|
itr = timeouts.erase(itr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace dht
|
|
|
|
} // namespace llarp
|
|
|
|
|
|
|
|
#endif
|