summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Efimov <[email protected]>2022-06-01 20:41:24 +0300
committerAlexey Efimov <[email protected]>2022-06-01 20:41:24 +0300
commit3d80db4ae60a700529a4e45d782862bb7d58e004 (patch)
treeae59ae9f47e61af61bbf3376877e70b8b86dd528
parent81eb0537a61f07cbf6835310688daff656c8b69c (diff)
add not so simple cache with lifetime checking KIKIMR-15015
ref:607a2c25f091e77893b82640122a16daa6ae3b1a
-rw-r--r--ydb/core/protos/auth.proto4
-rw-r--r--ydb/core/util/simple_cache.h93
-rw-r--r--ydb/core/util/simple_cache_ut.cpp31
3 files changed, 126 insertions, 2 deletions
diff --git a/ydb/core/protos/auth.proto b/ydb/core/protos/auth.proto
index 7ba2bc4bd54..ced6fc9bcc4 100644
--- a/ydb/core/protos/auth.proto
+++ b/ydb/core/protos/auth.proto
@@ -15,8 +15,8 @@ message TAuthConfig {
optional uint64 GrpcErrorLifeTime = 18 [default = 10000]; // ms
optional bool UseBlackBox = 20 [default = true];
optional bool UseAccessService = 21 [default = false];
- optional bool CacheAccessServiceAuthentication = 22 [default = true];
- optional bool CacheAccessServiceAuthorization = 23 [default = true];
+ optional bool CacheAccessServiceAuthentication = 22 [default = false];
+ optional bool CacheAccessServiceAuthorization = 23 [default = false];
optional bool UseStaff = 25 [default = true];
optional bool UseUserAccountService = 26 [default = false];
optional bool UseServiceAccountService = 27 [default = false];
diff --git a/ydb/core/util/simple_cache.h b/ydb/core/util/simple_cache.h
index 4190e8bb762..5083ba369e2 100644
--- a/ydb/core/util/simple_cache.h
+++ b/ydb/core/util/simple_cache.h
@@ -71,4 +71,97 @@ protected:
TList List_;
};
+template <typename TKey, typename TValue>
+class TNotSoSimpleCache {
+public:
+ size_t MaxSize = 1024;
+
+ struct TItem;
+
+ using TMap = std::unordered_map<TKey, TItem>;
+ using TMapIterator = typename TMap::iterator;
+ using TList = typename std::list<TMapIterator>;
+ using TListIterator = typename TList::iterator;
+
+ struct TItem {
+ TValue Value;
+ TListIterator ListIterator;
+ };
+
+ TValue* FindPtr(TKey key) {
+ auto it = Map_.find(key);
+ if (it != Map_.end()) {
+ Touch(it);
+ return &it->second.Value;
+ } else {
+ return nullptr;
+ }
+ }
+
+ TValue& Update(TKey key, TValue value = {}) {
+ auto it = Map_.find(key); // we don't use blind emplace to avoid coping value
+ if (it == Map_.end()) {
+ it = Map_.emplace(key, TItem{std::move(value), List_.end()}).first;
+ List_.emplace_back(it);
+ it->second.ListIterator = std::prev(List_.end());
+ Shrink();
+ } else {
+ it->second.Value = std::move(value);
+ Touch(it);
+ }
+ return it->second.Value;
+ }
+
+ void Erase(TKey key) {
+ auto it = Map_.find(key);
+ if (it != Map_.end()) {
+ List_.remove(it); // log(N)
+ Map_.erase(it);
+ }
+ }
+
+protected:
+ void Touch(TMapIterator it) {
+ List_.splice(List_.end(), List_, it->second.ListIterator);
+ it->second.ListIterator = std::prev(List_.end());
+ }
+
+ template<typename TVal, typename Enable = void>
+ struct TReleaseChecker {
+ bool operator ()(TVal&) const {
+ return true;
+ }
+ };
+
+ template<typename TVal>
+ struct TReleaseChecker<TVal, typename std::enable_if_t<std::is_invocable_v<decltype(&TVal::IsSafeToRelease), TVal&>>> {
+ bool operator ()(TVal& val) const {
+ return val.IsSafeToRelease();
+ }
+ };
+
+ static bool IsSafeToRelease(TValue& val) {
+ return TReleaseChecker<TValue>()(val);
+ }
+
+ void Shrink() {
+ size_t maxDepth = std::min<size_t>(MaxSize + 1, 10);
+ auto itList = List_.begin();
+ while (List_.size() > MaxSize && itList != List_.end()) {
+ if (IsSafeToRelease((*itList)->second.Value)) {
+ Map_.erase(*itList);
+ itList = List_.erase(itList);
+ } else {
+ ++itList;
+ if (--maxDepth == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ TMap Map_;
+ TList List_;
+};
+
} // NKikimr
diff --git a/ydb/core/util/simple_cache_ut.cpp b/ydb/core/util/simple_cache_ut.cpp
index 340d5226634..e799faeab60 100644
--- a/ydb/core/util/simple_cache_ut.cpp
+++ b/ydb/core/util/simple_cache_ut.cpp
@@ -22,6 +22,37 @@ Y_UNIT_TEST_SUITE(TSimpleCacheTest) {
ptr = cache.FindPtr("2");
UNIT_ASSERT(ptr == nullptr);
}
+
+ struct TValue {
+ TString Str;
+ bool SafeToRelease = true;
+
+ bool IsSafeToRelease() {
+ return SafeToRelease;
+ }
+ };
+
+ Y_UNIT_TEST(TestNotSoSimpleCache) {
+ TNotSoSimpleCache<TString, TValue> cache;
+
+ cache.MaxSize = 3;
+ TValue* ptr = cache.FindPtr("1");
+ UNIT_ASSERT(ptr == nullptr);
+ cache.Update("1", {"one"});
+ ptr = cache.FindPtr("1");
+ UNIT_ASSERT(ptr != nullptr);
+ UNIT_ASSERT(ptr->Str == "one");
+ cache.Update("2", {"two", false});
+ cache.Update("3", {"three"});
+ ptr = cache.FindPtr("1");
+ UNIT_ASSERT(ptr != nullptr);
+ UNIT_ASSERT(ptr->Str == "one");
+ cache.Update("4", {"four"}); // we evicting oldest one - "three" (but not "two" - it's not safe to release)
+ ptr = cache.FindPtr("2");
+ UNIT_ASSERT(ptr != nullptr);
+ ptr = cache.FindPtr("3");
+ UNIT_ASSERT(ptr == nullptr);
+ }
}
} // NKikimr