summaryrefslogtreecommitdiff
path: root/http/timer_queue.h
blob: d83cd0e22927091a551da53cec3167e414f92c89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#pragma once

#include "logging.h"

#include <boost/circular_buffer.hpp>
#include <boost/circular_buffer/space_optimized.hpp>

#include <chrono>
#include <functional>

namespace crow
{
namespace detail
{

constexpr const size_t timerQueueTimeoutSeconds = 5;
constexpr const size_t maxSize = 100;
// fast timer queue for fixed tick value.
class TimerQueue
{
  public:
    TimerQueue()
    {
        dq.set_capacity(maxSize);
    }

    void cancel(size_t k)
    {
        size_t index = k - step;
        if (index < dq.size())
        {
            dq[index].second = nullptr;
        }
    }

    std::optional<size_t> add(std::function<void()> f)
    {
        if (dq.size() == maxSize)
        {
            return std::nullopt;
        }

        dq.push_back(
            std::make_pair(std::chrono::steady_clock::now(), std::move(f)));
        size_t ret = step + dq.size() - 1;

        BMCWEB_LOG_DEBUG << "timer add inside: " << this << ' ' << ret;
        return ret;
    }

    void process()
    {
        auto now = std::chrono::steady_clock::now();
        while (!dq.empty())
        {
            auto& x = dq.front();
            // Check expiration time only for active handlers,
            // remove canceled ones immediately
            if (x.second)
            {
                if (now - x.first <
                    std::chrono::seconds(timerQueueTimeoutSeconds))
                {
                    break;
                }

                BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
                // we know that timer handlers are very simple currently; call
                // here
                x.second();
            }
            dq.pop_front();
            step++;
        }
    }

  private:
    using storage_type =
        std::pair<std::chrono::time_point<std::chrono::steady_clock>,
                  std::function<void()>>;

    boost::circular_buffer_space_optimized<storage_type,
                                           std::allocator<storage_type>>
        dq{};

    // boost::circular_buffer<storage_type> dq{20};
    // std::deque<storage_type> dq{};
    size_t step{};
};
} // namespace detail
} // namespace crow