lokinet/include/llarp/codel.hpp

192 lines
4.4 KiB
C++
Raw Normal View History

2018-06-26 01:30:36 +00:00
#ifndef LLARP_CODEL_QUEUE_HPP
#define LLARP_CODEL_QUEUE_HPP
#ifdef _MSC_VER
#define NOMINMAX
#ifdef min
#undef min
#endif
#endif
2018-06-26 01:30:36 +00:00
#include <llarp/time.h>
2018-07-19 04:58:39 +00:00
#include <llarp/logger.hpp>
2018-08-20 19:12:12 +00:00
#include <llarp/mem.hpp>
#include <llarp/threading.hpp>
2018-07-09 04:26:27 +00:00
#include <algorithm>
2018-06-26 01:30:36 +00:00
#include <cmath>
#include <functional>
2018-06-26 01:30:36 +00:00
#include <queue>
#include <string>
2018-06-26 01:30:36 +00:00
namespace llarp
{
namespace util
{
2018-07-02 19:24:22 +00:00
struct DummyMutex
{
};
struct DummyLock
{
2018-07-03 12:10:44 +00:00
DummyLock(const DummyMutex& mtx){};
2018-07-02 19:24:22 +00:00
~DummyLock()
{
}
};
2018-07-20 04:50:28 +00:00
template < typename T, typename GetTime >
struct CoDelCompareTime
{
bool
operator()(const T& left, const T& right) const
{
return GetTime()(left) < GetTime()(right);
}
};
2018-07-02 19:24:22 +00:00
2018-07-20 04:50:28 +00:00
template < typename T >
struct CoDelComparePriority
{
bool
operator()(const T& left, const T& right) const
{
return left < right;
}
};
template < typename T, typename GetTime, typename PutTime, typename Compare,
2018-08-12 17:22:29 +00:00
typename Mutex_t = util::Mutex, typename Lock_t = util::Lock,
2018-07-20 04:50:28 +00:00
llarp_time_t dropMs = 5, llarp_time_t initialIntervalMs = 100 >
2018-06-26 01:30:36 +00:00
struct CoDelQueue
{
CoDelQueue(const std::string& name) : m_name(name)
{
}
2018-07-02 19:24:22 +00:00
size_t
Size()
{
Lock_t lock(m_QueueMutex);
return m_Queue.size();
}
2018-08-20 19:12:12 +00:00
template < typename... Args >
bool
EmplaceIf(std::function< bool(T*) > pred, Args&&... args)
{
2018-08-22 15:52:10 +00:00
T* ptr = new T(std::forward< Args >(args)...);
if(!pred(ptr))
{
delete ptr;
2018-08-20 19:12:12 +00:00
return false;
2018-08-22 15:52:10 +00:00
}
PutTime()(ptr);
2018-08-20 19:12:12 +00:00
{
Lock_t lock(m_QueueMutex);
if(firstPut == 0)
2018-08-22 15:52:10 +00:00
firstPut = GetTime()(ptr);
m_Queue.push(ptr);
2018-08-20 19:12:12 +00:00
}
return true;
}
template < typename... Args >
void
Emplace(Args&&... args)
{
2018-08-22 15:52:10 +00:00
T* ptr = new T(std::forward< Args >(args)...);
PutTime()(ptr);
2018-08-20 19:12:12 +00:00
{
Lock_t lock(m_QueueMutex);
if(firstPut == 0)
2018-08-22 15:52:10 +00:00
firstPut = GetTime()(ptr);
m_Queue.push(ptr);
2018-08-20 19:12:12 +00:00
}
}
2018-06-26 01:30:36 +00:00
void
2018-08-22 15:52:10 +00:00
Put(T* ptr)
2018-06-26 01:30:36 +00:00
{
2018-08-22 15:52:10 +00:00
PutTime()(ptr);
2018-08-20 19:12:12 +00:00
{
Lock_t lock(m_QueueMutex);
if(firstPut == 0)
2018-08-22 15:52:10 +00:00
firstPut = GetTime()(ptr);
m_Queue.push(ptr);
2018-08-20 19:12:12 +00:00
}
2018-06-26 01:30:36 +00:00
}
/// visit returns true to discard entry otherwise the entry is
/// re quened
template < typename Visit >
void
ProcessIf(Visit visitor)
2018-06-26 01:30:36 +00:00
{
llarp_time_t lowest = 0xFFFFFFFFFFFFFFFFUL;
2018-06-29 12:15:15 +00:00
// auto start = llarp_time_now_ms();
// llarp::LogInfo("CoDelQueue::Process - start at ", start);
2018-07-02 19:24:22 +00:00
Lock_t lock(m_QueueMutex);
auto start = firstPut;
Queue_t requeue;
2018-06-26 01:30:36 +00:00
while(m_Queue.size())
{
2018-08-20 19:12:12 +00:00
llarp::LogDebug("CoDelQueue::Process - queue has ", m_Queue.size());
T* item = m_Queue.top();
2018-08-22 15:52:10 +00:00
auto dlt = start - GetTime()(item);
// llarp::LogInfo("CoDelQueue::Process - dlt ", dlt);
2018-06-29 12:15:15 +00:00
lowest = std::min(dlt, lowest);
2018-06-26 01:30:36 +00:00
if(m_Queue.size() == 1)
{
// llarp::LogInfo("CoDelQueue::Process - single item: lowest ",
// lowest, " dropMs: ", dropMs);
2018-06-26 01:30:36 +00:00
if(lowest > dropMs)
{
2018-06-26 13:39:29 +00:00
nextTickInterval += initialIntervalMs / std::sqrt(++dropNum);
2018-06-26 01:30:36 +00:00
m_Queue.pop();
2018-08-22 15:52:10 +00:00
delete item;
break;
2018-06-26 01:30:36 +00:00
}
else
{
nextTickInterval = initialIntervalMs;
dropNum = 0;
}
}
// llarp::LogInfo("CoDelQueue::Process - passing");
if(visitor(item))
{
delete item;
2018-08-22 15:52:10 +00:00
}
else
{
requeue.push(item);
}
2018-06-26 01:30:36 +00:00
m_Queue.pop();
}
m_Queue = std::move(requeue);
firstPut = 0;
2018-06-26 01:30:36 +00:00
}
template < typename Func >
void
Process(Func visitor)
{
2018-08-22 15:52:10 +00:00
ProcessIf([visitor](T* t) -> bool {
visitor(t);
return true;
});
}
llarp_time_t firstPut = 0;
2018-06-26 01:30:36 +00:00
size_t dropNum = 0;
llarp_time_t nextTickInterval = initialIntervalMs;
2018-07-02 19:24:22 +00:00
Mutex_t m_QueueMutex;
typedef std::priority_queue< T*, std::vector< T* >, Compare > Queue_t;
Queue_t m_Queue;
std::string m_name;
2018-06-26 01:30:36 +00:00
};
} // namespace util
} // namespace llarp
#endif