aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/actors/util/local_process_key.h
blob: 077de8cddc29b595bdf2b304bb90bf7c8d24f331 (plain) (blame)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#pragma once

#include <util/string/builder.h>
#include <util/system/mutex.h>
#include <util/generic/strbuf.h>
#include <util/generic/vector.h>
#include <util/generic/hash.h>
#include <util/generic/singleton.h>
#include <util/generic/serialized_enum.h>

class TLocalProcessKeyStateIndexLimiter {
public:
    static constexpr ui32 GetMaxKeysCount() {
        return 10000;
    }
};

template <class T>
class TLocalProcessKeyStateIndexConstructor {
public:
};

template <typename T>
class TLocalProcessKeyState {

template <typename U, const char* Name>
friend class TLocalProcessKey;
template <typename U, class TClass, ui32 KeyLengthLimit>
friend class TLocalProcessExtKey;
template <typename U, typename EnumT>
friend class TEnumProcessKey;

public:
    static TLocalProcessKeyState& GetInstance() {
        return *Singleton<TLocalProcessKeyState<T>>();
    }

    ui32 GetCount() const {
        return MaxKeysCount;
    }

    TStringBuf GetNameByIndex(size_t index) const {
        Y_VERIFY(index < Names.size());
        return Names[index];
    }

    size_t GetIndexByName(TStringBuf name) const {
        TGuard<TMutex> g(Mutex);
        auto it = Map.find(name);
        Y_ENSURE(it != Map.end());
        return it->second;
    }

    TLocalProcessKeyState() {
        Names.resize(MaxKeysCount);
    }

    size_t Register(TStringBuf name) {
        TGuard<TMutex> g(Mutex);
        auto it = Map.find(name);
        if (it != Map.end()) {
            return it->second;
        }
        const ui32 index = TLocalProcessKeyStateIndexConstructor<T>::BuildCurrentIndex(name, Names.size());
        auto x = Map.emplace(name, index);
        if (x.second) {
            Y_VERIFY(index < Names.size(), "a lot of actors or tags for memory monitoring");
            Names[index] = name;
        }

        return x.first->second;
    }

private:

    static constexpr ui32 MaxKeysCount = TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount();

private:
    TVector<TString> Names;
    THashMap<TString, size_t> Map;
    TMutex Mutex;
};

template <typename T, const char* Name>
class TLocalProcessKey {
public:
    static TStringBuf GetName() {
        return Name;
    }

    static size_t GetIndex() {
        return Index;
    }

private:
    inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(Name);
};

template <typename T, class TClass, ui32 KeyLengthLimit = 0>
class TLocalProcessExtKey {
public:
    static TStringBuf GetName() {
        return Name;
    }

    static size_t GetIndex() {
        return Index;
    }

private:

    static TString TypeNameRobust() {
        const TString className = TypeName<TClass>();
        if (KeyLengthLimit && className.size() > KeyLengthLimit) {
            return className.substr(0, KeyLengthLimit - 3) + "...";
        } else {
            return className;
        }
    }

    static const inline TString Name = TypeName<TClass>();
    inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(TypeNameRobust());
};

template <typename T, typename EnumT>
class TEnumProcessKey {
public:
    static TStringBuf GetName(const EnumT key) {
        return TLocalProcessKeyState<T>::GetInstance().GetNameByIndex(GetIndex(key));
    }

    static size_t GetIndex(const EnumT key) {
        ui32 index = static_cast<ui32>(key);
        Y_VERIFY(index < Enum2Index.size());
        return Enum2Index[index];
    }

private:
    inline static TVector<size_t> RegisterAll() {
        static_assert(std::is_enum<EnumT>::value, "Enum is required");

        TVector<size_t> enum2Index;
        auto names = GetEnumNames<EnumT>();
        ui32 maxId = 0;
        for (const auto& [k, v] : names) {
            maxId = Max(maxId, static_cast<ui32>(k));
        }
        enum2Index.resize(maxId + 1);
        for (const auto& [k, v] : names) {
            ui32 enumId = static_cast<ui32>(k);
            enum2Index[enumId] = TLocalProcessKeyState<T>::GetInstance().Register(v);
        }
        return enum2Index;
    }

    inline static TVector<size_t> Enum2Index = RegisterAll();
};