fix expire cache
All checks were successful
linux-mips64-gcc / linux-gcc-mips64el (Debug) (push) Successful in 1m30s
linux-aarch64-cpu-gcc / linux-gcc-aarch64 (push) Successful in 1m50s
linux-arm-gcc / linux-gcc-armhf (push) Successful in 2m15s
linux-x64-gcc / linux-gcc (Release) (push) Successful in 2m22s
linux-x64-gcc / linux-gcc (Debug) (push) Successful in 2m24s
linux-mips64-gcc / linux-gcc-mips64el (Release) (push) Successful in 3m6s

This commit is contained in:
tqcq 2024-04-12 23:53:01 +08:00
parent 0bafdc98c7
commit 794535e9a1
8 changed files with 107 additions and 40 deletions

View File

@ -201,8 +201,10 @@ if(SLED_BUILD_TESTS)
sled_add_test(NAME sled_ioc_test SRCS src/sled/ioc/ioc_test.cc)
sled_add_test(NAME sled_inja_test SRCS src/sled/nonstd/inja_test.cc)
sled_add_test(NAME sled_fsm_test SRCS src/sled/nonstd/fsm_test.cc)
sled_add_test(NAME sled_cache_test SRCS src/sled/cache/lru_cache_test.cc
src/sled/cache/fifo_cache_test.cc)
sled_add_test(NAME sled_timestamp_test SRCS src/sled/units/timestamp_test.cc)
sled_add_test(
NAME sled_cache_test SRCS src/sled/cache/lru_cache_test.cc
src/sled/cache/fifo_cache_test.cc src/sled/cache/expire_cache_test.cc)
endif(SLED_BUILD_TESTS)
if(SLED_BUILD_FUZZ)

View File

@ -9,6 +9,11 @@ namespace sled {
template<typename TKey, typename TValue>
class ExpireCache : public AbstractCache<TKey, TValue, ExpireCachePolicy<TKey>> {
public:
ExpireCache(const TimeDelta &expire_time)
{
this->policy_.insert(std::make_shared<ExpireCachePolicy<TKey>>(expire_time));
}
~ExpireCache() override = default;
};
}// namespace sled

18
src/sled/cache/expire_cache_test.cc vendored Normal file
View File

@ -0,0 +1,18 @@
#include <sled/cache/expire_cache.h>
#include <sled/system/thread.h>
TEST_SUITE("Expire Cache")
{
TEST_CASE("Remove Expired Key")
{
sled::ExpireCache<int, int> expire_cache(sled::TimeDelta::Millis(25));
expire_cache.Add(1, 1);
REQUIRE(expire_cache.Has(1));
CHECK_EQ(*expire_cache.Get(1), 1);
sled::Thread::SleepMs(30);
CHECK_FALSE(expire_cache.Has(1));
CHECK(expire_cache.empty());
CHECK_EQ(expire_cache.Get(1), nullptr);
}
}

View File

@ -3,7 +3,6 @@
#pragma once
#include "abstract_cache_policy.h"
#include "sled/time_utils.h"
#include "sled/units/timestamp.h"
#include <map>
@ -12,12 +11,14 @@ namespace sled {
template<typename TKey>
class ExpireCachePolicy : public AbstractCachePolicy<TKey> {
public:
ExpireCachePolicy(const TimeDelta &expire_time) : expire_time_(expire_time) {}
~ExpireCachePolicy() override = default;
void OnAdd(const TKey &key) override
{
Timestamp now = Timestamp::Nanos(TimeNanos());
auto iter = key_index_.insert(std::make_pair(now, key));
Timestamp cur_expire_time = Timestamp::Now() + expire_time_;
auto iter = key_index_.insert(std::make_pair(cur_expire_time, key));
keys_[key] = iter;
}
@ -44,8 +45,7 @@ public:
void OnReplace(std::set<TKey> &elems_to_remove) override
{
auto iter = key_index_.begin();
Timestamp now = Timestamp::Nanos(TimeNanos());
while (iter != key_index_.end() && iter->first < now) {
while (iter != key_index_.end() && iter->first.IsExpired()) {
elems_to_remove.insert(iter->second);
++iter;
}
@ -54,15 +54,11 @@ public:
bool IsValid(const TKey &key) override
{
auto iter = keys_.find(key);
if (iter != keys_.end()) {
return iter->second->first + expire_time_ > Timestamp::Nanos(TimeNanos());
} else {
return false;
}
return iter != keys_.end() && !iter->second->first.IsExpired();
}
private:
TimeDelta expire_time_;
const TimeDelta expire_time_;
std::multimap<Timestamp, TKey> key_index_;
std::map<TKey, typename std::multimap<Timestamp, TKey>::iterator> keys_;
};

View File

@ -41,9 +41,18 @@ public:
BaseClass::OnClear();
}
void OnReplace(std::set<TKey> &key) override
void OnReplace(std::set<TKey> &elems_to_remove) override
{
// do nothing
BaseClass::OnReplace(elems_to_remove);
if (keys_.size() <= size_) { return; }
std::size_t diff = keys_.size() - size_;
std::size_t index = 0;
auto iter = keys_.begin();
while (index++ < diff) {
elems_to_remove.insert(*iter);
if (iter != keys_.end()) { ++iter; }
}
}
bool IsValid(const TKey &key) override { return BaseClass::IsValid(key); }

View File

@ -27,18 +27,25 @@ public:
static constexpr TimeDelta Seconds(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000000, value);
return FromFraction(1000000000, value);
}
template<typename T>
static constexpr TimeDelta Millis(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000, value);
return FromFraction(1000000, value);
}
template<typename T>
static constexpr TimeDelta Micros(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000, value);
}
template<typename T>
static constexpr TimeDelta Nanos(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
@ -47,7 +54,7 @@ public:
template<typename Clock, typename Duration>
inline TimeDelta(const std::chrono::duration<Clock, Duration> &duration)
{
*this = FromValue(std::chrono::duration_cast<std::chrono::microseconds>(duration).count());
*this = FromValue(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count());
}
TimeDelta() = delete;
@ -55,32 +62,34 @@ public:
template<typename T = int64_t>
constexpr T seconds() const
{
return ToFraction<1000000, T>();
return ToFraction<1000000000, T>();
}
template<typename T = int64_t>
constexpr T ms() const
{
return ToFraction<1000, T>();
return ToFraction<1000000, T>();
}
template<typename T = int64_t>
constexpr T us() const
{
return ToValue<T>();
return ToFraction<1000, T>();
}
template<typename T = int64_t>
constexpr T ns() const
{
return ToMultiple<1000, T>();
return ToValue<T>();
}
constexpr int64_t seconds_or(int64_t fallback_value) const { return ToFractionOr<1000000>(fallback_value); }
constexpr int64_t seconds_or(int64_t fallback_value) const { return ToFractionOr<1000000000>(fallback_value); }
constexpr int64_t ms_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); }
constexpr int64_t ms_or(int64_t fallback_value) const { return ToFractionOr<1000000>(fallback_value); }
constexpr int64_t us_or(int64_t fallback_value) const { return ToValueOr(fallback_value); }
constexpr int64_t us_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); }
constexpr int64_t ns_or(int64_t fallback_value) const { return ToValueOr(fallback_value); }
constexpr TimeDelta Abs() const { return us() < 0 ? TimeDelta::Micros(-us()) : *this; }

View File

@ -7,6 +7,7 @@
#pragma once
#ifndef SLED_UNITS_TIMESTAMP_H
#define SLED_UNITS_TIMESTAMP_H
#include "sled/time_utils.h"
#include "sled/units/time_delta.h"
#include "sled/units/unit_base.h"
@ -14,65 +15,71 @@ namespace sled {
class Timestamp final : public detail::UnitBase<Timestamp> {
public:
static Timestamp Now() { return Timestamp::Nanos(TimeNanos()); }
template<typename T>
static constexpr Timestamp Seconds(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000000, value);
return FromFraction(1000000000, value);
}
template<typename T>
static constexpr Timestamp Millis(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000, value);
return FromFraction(1000000, value);
}
template<typename T>
static constexpr Timestamp Micros(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
return FromFraction(1000, value);
}
template<typename T>
static constexpr Timestamp Nanos(T value)
{
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value * 1000LL);
return FromValue(value);
}
Timestamp() = delete;
bool IsExpired() const { return *this < Now(); }
template<typename T = int64_t>
constexpr T seconds() const
{
return ToFraction<1000000, T>();
return ToFraction<1000000000, T>();
}
template<typename T = int64_t>
constexpr T ms() const
{
return ToFraction<1000, T>();
return ToFraction<1000000, T>();
}
template<typename T = int64_t>
constexpr T us() const
{
return ToValue<T>();
return ToFraction<1000, T>();
}
template<typename T = int64_t>
constexpr T ns() const
{
return ToMultiple<1000, T>();
return ToValue<T>();
}
constexpr int64_t seconds_or(int64_t fallback_value) const { return ToFractionOr<1000000>(fallback_value); }
constexpr int64_t seconds_or(int64_t fallback_value) const { return ToFractionOr<1000000000>(fallback_value); }
constexpr int64_t ms_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); }
constexpr int64_t ms_or(int64_t fallback_value) const { return ToFractionOr<1000000>(fallback_value); }
constexpr int64_t us_or(int64_t fallback_value) const { return ToValueOr(fallback_value); }
constexpr int64_t us_or(int64_t fallback_value) const { return ToFractionOr<1000>(fallback_value); }
constexpr int64_t ns_or(int64_t fallback_value) const { return ToValueOr(fallback_value); }
Timestamp operator+(const TimeDelta delta) const
{
@ -81,7 +88,7 @@ public:
} else if (IsMinusInfinity() || delta.IsMinusInfinity()) {
return MinusInfinity();
}
return Timestamp::Micros(us() - delta.us());
return Timestamp::Nanos(ns() + delta.ns());
}
Timestamp operator-(const TimeDelta delta) const
@ -91,7 +98,7 @@ public:
} else if (IsMinusInfinity() || delta.IsPlusInfinity()) {
return MinusInfinity();
}
return Timestamp::Micros(us() - delta.us());
return Timestamp::Nanos(ns() - delta.ns());
}
TimeDelta operator-(const Timestamp other) const

View File

@ -0,0 +1,21 @@
#include <sled/units/timestamp.h>
TEST_SUITE("Timestamp")
{
TEST_CASE("ToString")
{
CHECK_EQ(sled::ToString(sled::Timestamp::PlusInfinity()), "+inf ms");
CHECK_EQ(sled::ToString(sled::Timestamp::MinusInfinity()), "-inf ms");
CHECK_EQ(sled::ToString(sled::Timestamp::Micros(1)), "1 us");
CHECK_EQ(sled::ToString(sled::Timestamp::Millis(1)), "1 ms");
CHECK_EQ(sled::ToString(sled::Timestamp::Seconds(1)), "1 s");
}
TEST_CASE("IsExpired")
{
auto passed = sled::Timestamp::Now() - sled::TimeDelta::Millis(1);
CHECK(passed.IsExpired());
auto future = sled::Timestamp::Now() + sled::TimeDelta::Millis(1);
CHECK_FALSE(future.IsExpired());
}
}