<commit_before>//----------------------------------------------------------------------------
/// \file   rate_throttler.hpp
/// \author <NAME>
//----------------------------------------------------------------------------
/// \brief Efficiently calculates the throttling rate over a number of seconds.
///
/// The algorithm implements a variation of token bucket algorithm that
/// doesn't require to add tokens to the bucket on a timer but rather it
/// maintains a circular buffer of tokens with resolution of 1/BucketsPerSec.
/// The basic_rate_throttler::add() function is used to adds items to a bucket
/// associated with the timestamp passed as the first argument to the
/// function.  The throttler::running_sum() returns the total number of
/// items over the given interval of seconds.
/// \note See also this article on a throttling algorithm
/// http://www.devquotes.com/2010/11/24/an-efficient-network-throttling-algorithm.
/// \note Another article on rate limiting
/// http://www.pennedobjects.com/2010/10/better-rate-limiting-with-dot-net.
//----------------------------------------------------------------------------
// Created: 2011-01-20
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2011 <NAME> <<EMAIL>>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_THROTTLER_HPP_
#define _UTXX_THROTTLER_HPP_

#include <utxx/error.hpp>
#include <utxx/meta.hpp>
#include <utxx/time_val.hpp>
#include <utxx/compiler_hints.hpp>
#include <time.h>

namespace utxx {

/// @brief Throttle given rate over a number of seconds.
/// Implementation uses time spacing reservation algorithm where each
/// allocation of samples reserves a fraction of space in the throttling
/// window. The reservation gets freed as the time goes by.  No more than
/// the "rate()" number of samples are allowed to fit in the "window_msec()"
/// window.
template <typename T = uint32_t>
class basic_time_spacing_throttle {
public:
    basic_time_spacing_throttle(uint32_t a_rate, uint32_t a_window_msec = 1000,
                          time_val a_now = now_utc())
        : m_rate        (a_rate)
        , m_window_us   (a_window_msec * 1000)
        , m_step_us     (m_window_us / m_rate)
        , m_next_time   (a_now)
    {}

    /// Add \a a_samples to the throtlle's counter.
    /// @return number of samples that fit in the throttling window. 0 means
    /// that the throttler is fully congested, and more time needs to elapse
    /// before the throttles gets reset to accept more samples.
    T add(T a_samples  = 1, time_val a_now = now_utc()) {
        auto next_time = m_next_time;
        next_time.add_usec(a_samples * m_step_us);
        auto diff      = next_time.microseconds()
                       - (a_now.microseconds() + m_window_us);
        if (diff < 0)  {
            // All samples fit the throttling threshold
            m_next_time = next_time;
            return a_samples;
        }

        // Figure out how many samples fit the throttling threshold
        auto n = std::max<T>(0, a_samples - (T(diff) / m_step_us));
        m_next_time.add_usec(n * m_step_us);
        return n;
    }

    T        rate()        const { return m_rate;             }
    long     step()        const { return m_step_us;          }
    long     window_msec() const { return m_window_us / 1000; }
    long     window_usec() const { return m_window_us;        }
    time_val next_time()   const { return m_next_time;        }

    /// Return the number of available samples given \a a_now current time.
    T        available(time_val a_now = now_utc()) const{
        auto   diff = (a_now - m_next_time).microseconds();
        return diff >= 0 ? m_rate : T(m_window_us + diff) / m_step_us;
    }
<commit_msg>Update rate_throttler.hpp<commit_after>//----------------------------------------------------------------------------
/// \file   rate_throttler.hpp
/// \author <NAME>
//----------------------------------------------------------------------------
/// \brief Efficiently calculates the throttling rate over a number of seconds.
///
/// The algorithm implements a variation of token bucket algorithm that
/// doesn't require to add tokens to the bucket on a timer but rather it
/// maintains a circular buffer of tokens with resolution of 1/BucketsPerSec.
/// The basic_rate_throttler::add() function is used to adds items to a bucket
/// associated with the timestamp passed as the first argument to the
/// function.  The throttler::running_sum() returns the total number of
/// items over the given interval of seconds.
/// \note See also this article on a throttling algorithm
/// http://www.devquotes.com/2010/11/24/an-efficient-network-throttling-algorithm.
/// \note Another article on rate limiting
/// http://www.pennedobjects.com/2010/10/better-rate-limiting-with-dot-net.
//----------------------------------------------------------------------------
// Created: 2011-01-20
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2011 <NAME> <<EMAIL>>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_THROTTLER_HPP_
#define _UTXX_THROTTLER_HPP_

#include <utxx/error.hpp>
#include <utxx/meta.hpp>
#include <utxx/time_val.hpp>
#include <utxx/compiler_hints.hpp>
#include <time.h>

namespace utxx {

/// @brief Throttle given rate over a number of seconds.
/// Implementation uses time spacing reservation algorithm where each
/// allocation of samples reserves a fraction of space in the throttling
/// window. The reservation gets freed as the time goes by.  No more than
/// the "rate()" number of samples are allowed to fit in the "window_msec()"
/// window.
template <typename T = uint32_t>
class basic_time_spacing_throttle {
public:
    basic_time_spacing_throttle(uint32_t a_rate, uint32_t a_window_msec = 1000,
                          time_val a_now = now_utc())
        : m_rate        (a_rate)
        , m_window_us   (a_window_msec * 1000)
        , m_step_us     (m_window_us / m_rate)
        , m_next_time   (a_now)
    {}

    /// Add \a a_samples to the throtlle's counter.
    /// @return number of samples that fit in the throttling window. 0 means
    /// that the throttler is fully congested, and more time needs to elapse
    /// before the throttles gets reset to accept more samples.
    T add(T a_samples  = 1, time_val a_now = now_utc()) {
        auto next_time = m_next_time;
        next_time.add_usec(a_samples * m_step_us);
        auto diff      = next_time.microseconds()
                       - (a_now.microseconds() + m_window_us);
        if (diff < 0)  {
            // All samples fit the throttling threshold
            m_next_time = next_time;
            return a_samples;
        }

        // Figure out how many samples fit the throttling threshold
        auto n = std::max<T>(0, a_samples - (T(diff) / m_step_us));
        m_next_time.add_usec(n * m_step_us);
        return n;
    }

    T        rate()        const { return m_rate;             }
    long     step()        const { return m_step_us;          }
    long     window_msec() const { return m_window_us / 1000; }
    long     window_usec() const { return m_window_us;        }
    time_val next_time()   const { return m_next_time;        }

    /// Return the number of available samples given \a a_now current time.
    T        available(time_val a_now = now_utc()) const      {
        auto   diff = (a_now - m_next_time).microseconds();
        return diff >= 0 ? m_rate : T(m_window_us + diff) / m_step_us;
    }

{'fraction_non_alphanumeric': 0.151964011411016, 'fraction_numerical': 0.014483212639894667, 'mean_word_length': 2.168230795968022, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '102067', 'n_tokens_mistral': 2683, 'n_tokens_neox': 2502, 'n_words': 959}