Skip to content

Commit 1d2901d

Browse files
committed
Add and use ExpiringFlatHashMap::access.
1 parent 9d92b49 commit 1d2901d

6 files changed

Lines changed: 110 additions & 46 deletions

File tree

‎td/telegram/MessagesManager.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21079,7 +21079,8 @@ MessageId MessagesManager::get_persistent_message_id(const Dialog *d, MessageId
2107921079
if (message_id.is_yet_unsent()) {
2108021080
// it is possible that user tries to do something with an already sent message by its temporary identifier
2108121081
// we need to use real message in this case and transparently replace message_id
21082-
auto *persistent_message_id = yet_unsent_message_full_id_to_persistent_message_id_.get({d->dialog_id, message_id});
21082+
auto *persistent_message_id =
21083+
yet_unsent_message_full_id_to_persistent_message_id_.access({d->dialog_id, message_id});
2108321084
if (persistent_message_id != nullptr) {
2108421085
return *persistent_message_id;
2108521086
}

‎td/telegram/UserManager.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7989,7 +7989,7 @@ void UserManager::can_send_message_to_user(UserId user_id, bool force,
79897989
return promise.set_value(td_api::make_object<td_api::canSendMessageToUserResultOk>());
79907990
}
79917991

7992-
auto *contact_price = user_full_contact_price_.get(user_id);
7992+
auto *contact_price = user_full_contact_price_.access(user_id);
79937993
if (contact_price != nullptr) {
79947994
if (*contact_price > 0) {
79957995
return promise.set_value(
@@ -8051,7 +8051,7 @@ void UserManager::allow_send_message_to_user(UserId user_id) {
80518051
CHECK(!td_->auth_manager_->is_bot());
80528052
if (get_user_full(user_id) == nullptr) {
80538053
CHECK(user_id.is_valid());
8054-
auto *contact_price = user_full_contact_price_.get(user_id);
8054+
auto *contact_price = user_full_contact_price_.access(user_id);
80558055
if (contact_price != nullptr && *contact_price == -1) {
80568056
*contact_price = 0;
80578057
}

‎tdutils/td/utils/ExpiringFlatHashMap.h‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,25 @@ class ExpiringFlatHashMap {
5454
explicit ExpiringFlatHashMap(double expire_time) : expire_time_(expire_time) {
5555
}
5656

57-
// returns nullptr if the item isn't found; the pointer is valid until the next call to a non-const method
57+
// returns nullptr if the item isn't found or has expired; doesn't update access time of the item
58+
// the pointer is valid until the next call to a non-const method
5859
ValueT *get(const KeyT &key) {
60+
auto now = Time::now();
61+
drop_expired_items(now);
62+
auto it = map_.find(key);
63+
if (it == map_.end()) {
64+
return nullptr;
65+
}
66+
auto *node = it->second.get();
67+
if (node->access_time_ + expire_time_ <= now) {
68+
return nullptr;
69+
}
70+
return &node->value_;
71+
}
72+
73+
// returns nullptr if the item isn't found; updates access time of the item
74+
// the pointer is valid until the next call to a non-const method
75+
ValueT *access(const KeyT &key) {
5976
auto now = Time::now();
6077
drop_expired_items(now);
6178
auto it = map_.find(key);

‎tdutils/td/utils/ExpiringWaitFreeHashMap.h‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,24 @@ class ExpiringWaitFreeHashMap {
5555
explicit ExpiringWaitFreeHashMap(double expire_time) : expire_time_(expire_time) {
5656
}
5757

58-
// returns nullptr if the item isn't found; the pointer is valid until the next call to a non-const method
58+
// returns nullptr if the item isn't found or has expired; doesn't update access time of the item
59+
// the pointer is valid until the next call to a non-const method
5960
ValueT *get(const KeyT &key) {
61+
auto now = Time::now();
62+
drop_expired_items(now);
63+
auto *node = map_.get_pointer(key);
64+
if (node == nullptr) {
65+
return nullptr;
66+
}
67+
if (node->access_time_ + expire_time_ <= now) {
68+
return nullptr;
69+
}
70+
return &node->value_;
71+
}
72+
73+
// returns nullptr if the item isn't found; updates access time of the item
74+
// the pointer is valid until the next call to a non-const method
75+
ValueT *access(const KeyT &key) {
6076
auto now = Time::now();
6177
drop_expired_items(now);
6278
auto *node = map_.get_pointer(key);

‎tdutils/test/ExpiringFlatHashMap.cpp‎

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@
1212
TEST(ExpiringFlatHashMap, basic) {
1313
td::ExpiringFlatHashMap<int, td::string> map(1e9);
1414
ASSERT_TRUE(map.empty());
15-
ASSERT_TRUE(map.get(1) == nullptr);
15+
ASSERT_TRUE(map.access(1) == nullptr);
1616
map.set(1, "a");
1717
map.set(2, "b");
1818
ASSERT_EQ(2u, map.size());
19-
ASSERT_EQ("a", *map.get(1));
19+
ASSERT_EQ("a", *map.access(1));
2020
map.set(1, "c");
21-
ASSERT_EQ("c", *map.get(1));
21+
ASSERT_EQ("c", *map.access(1));
2222
ASSERT_EQ(1u, map.erase(2));
2323
ASSERT_EQ(0u, map.erase(2));
24-
ASSERT_TRUE(map.get(2) == nullptr);
24+
ASSERT_TRUE(map.access(2) == nullptr);
2525
ASSERT_EQ(1u, map.size());
2626
map.clear();
2727
ASSERT_TRUE(map.empty());
@@ -34,16 +34,16 @@ TEST(ExpiringFlatHashMap, expiration) {
3434
}
3535
ASSERT_EQ(25u, map.size());
3636
td::Time::jump_in_future(td::Time::now() + 6.0);
37-
ASSERT_EQ(1, *map.get(1));
37+
ASSERT_EQ(1, *map.access(1));
3838
td::Time::jump_in_future(td::Time::now() + 6.0);
3939
// items 2-25 are expired, but only 10 of them can be dropped during a call
40-
ASSERT_TRUE(map.get(26) == nullptr);
40+
ASSERT_TRUE(map.access(26) == nullptr);
4141
ASSERT_EQ(15u, map.size());
42-
ASSERT_TRUE(map.get(26) == nullptr);
42+
ASSERT_TRUE(map.access(26) == nullptr);
4343
ASSERT_EQ(5u, map.size());
44-
ASSERT_TRUE(map.get(26) == nullptr);
44+
ASSERT_TRUE(map.access(26) == nullptr);
4545
ASSERT_EQ(1u, map.size());
46-
ASSERT_EQ(1, *map.get(1));
46+
ASSERT_EQ(1, *map.access(1));
4747
}
4848

4949
TEST(ExpiringFlatHashMap, operator_brackets) {
@@ -52,14 +52,14 @@ TEST(ExpiringFlatHashMap, operator_brackets) {
5252
ASSERT_EQ(1u, map.size());
5353
map[1] = 5;
5454
map[2]++;
55-
ASSERT_EQ(5, *map.get(1));
55+
ASSERT_EQ(5, *map.access(1));
5656
ASSERT_EQ(1, map[2]);
5757
ASSERT_EQ(2u, map.size());
5858
td::Time::jump_in_future(td::Time::now() + 6.0);
5959
map[1] += 1;
6060
td::Time::jump_in_future(td::Time::now() + 6.0);
6161
// item 2 is expired, but item 1 was accessed through operator[] recently
62-
ASSERT_TRUE(map.get(3) == nullptr);
62+
ASSERT_TRUE(map.access(3) == nullptr);
6363
ASSERT_EQ(1u, map.size());
6464
ASSERT_EQ(6, map[1]);
6565
ASSERT_EQ(0, map[2]);
@@ -83,29 +83,44 @@ TEST(ExpiringFlatHashMap, clear) {
8383
map.clear();
8484
ASSERT_TRUE(map.empty());
8585
ASSERT_EQ(0u, map.size());
86-
ASSERT_TRUE(map.get(1) == nullptr);
86+
ASSERT_TRUE(map.access(1) == nullptr);
8787
ASSERT_EQ(0u, map.erase(2));
8888

8989
map.set(1, 10);
9090
map[2] = 20;
91-
ASSERT_EQ(10, *map.get(1));
91+
ASSERT_EQ(10, *map.access(1));
9292
ASSERT_EQ(20, map[2]);
9393
ASSERT_EQ(0, map[3]);
9494
ASSERT_EQ(3u, map.size());
9595
td::Time::jump_in_future(td::Time::now() + 6.0);
96-
ASSERT_EQ(10, *map.get(1));
96+
ASSERT_EQ(10, *map.access(1));
9797
td::Time::jump_in_future(td::Time::now() + 6.0);
9898
// only items added after clear are dropped
99-
ASSERT_TRUE(map.get(4) == nullptr);
99+
ASSERT_TRUE(map.access(4) == nullptr);
100100
ASSERT_EQ(1u, map.size());
101-
ASSERT_EQ(10, *map.get(1));
101+
ASSERT_EQ(10, *map.access(1));
102102

103103
map.clear();
104104
map.clear();
105105
ASSERT_TRUE(map.empty());
106106
map.set(5, 50);
107107
ASSERT_EQ(1u, map.size());
108-
ASSERT_EQ(50, *map.get(5));
108+
ASSERT_EQ(50, *map.access(5));
109109
ASSERT_EQ(1u, map.erase(5));
110110
ASSERT_TRUE(map.empty());
111111
}
112+
113+
TEST(ExpiringFlatHashMap, get) {
114+
td::ExpiringFlatHashMap<int, int> map(10.0);
115+
map.set(1, 1);
116+
map.set(2, 2);
117+
ASSERT_EQ(1, *map.get(1));
118+
ASSERT_TRUE(map.get(3) == nullptr);
119+
td::Time::jump_in_future(td::Time::now() + 6.0);
120+
ASSERT_EQ(1, *map.get(1)); // doesn't update access time
121+
ASSERT_EQ(2, *map.access(2)); // updates access time
122+
td::Time::jump_in_future(td::Time::now() + 6.0);
123+
ASSERT_TRUE(map.get(1) == nullptr); // the expired item is dropped
124+
ASSERT_EQ(1u, map.size());
125+
ASSERT_EQ(2, *map.get(2));
126+
}

‎tdutils/test/ExpiringWaitFreeHashMap.cpp‎

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@
1212
TEST(ExpiringWaitFreeHashMap, basic) {
1313
td::ExpiringWaitFreeHashMap<int, td::string> map(1e9);
1414
ASSERT_TRUE(map.empty());
15-
ASSERT_TRUE(map.get(1) == nullptr);
15+
ASSERT_TRUE(map.access(1) == nullptr);
1616
map.set(1, "a");
1717
map.set(2, "b");
1818
ASSERT_EQ(2u, map.calc_size());
19-
ASSERT_EQ("a", *map.get(1));
19+
ASSERT_EQ("a", *map.access(1));
2020
map.set(1, "c");
21-
ASSERT_EQ("c", *map.get(1));
21+
ASSERT_EQ("c", *map.access(1));
2222
ASSERT_EQ(1u, map.erase(2));
2323
ASSERT_EQ(0u, map.erase(2));
24-
ASSERT_TRUE(map.get(2) == nullptr);
24+
ASSERT_TRUE(map.access(2) == nullptr);
2525
ASSERT_EQ(1u, map.calc_size());
2626
map.clear();
2727
ASSERT_TRUE(map.empty());
2828
map.set(3, "d");
29-
ASSERT_EQ("d", *map.get(3));
29+
ASSERT_EQ("d", *map.access(3));
3030
}
3131

3232
TEST(ExpiringWaitFreeHashMap, expiration) {
@@ -36,16 +36,16 @@ TEST(ExpiringWaitFreeHashMap, expiration) {
3636
}
3737
ASSERT_EQ(25u, map.calc_size());
3838
td::Time::jump_in_future(td::Time::now() + 6.0);
39-
ASSERT_EQ(1, *map.get(1));
39+
ASSERT_EQ(1, *map.access(1));
4040
td::Time::jump_in_future(td::Time::now() + 6.0);
4141
// items 2-25 are expired, but only 10 of them can be dropped during a call
42-
ASSERT_TRUE(map.get(26) == nullptr);
42+
ASSERT_TRUE(map.access(26) == nullptr);
4343
ASSERT_EQ(15u, map.calc_size());
44-
ASSERT_TRUE(map.get(26) == nullptr);
44+
ASSERT_TRUE(map.access(26) == nullptr);
4545
ASSERT_EQ(5u, map.calc_size());
46-
ASSERT_TRUE(map.get(26) == nullptr);
46+
ASSERT_TRUE(map.access(26) == nullptr);
4747
ASSERT_EQ(1u, map.calc_size());
48-
ASSERT_EQ(1, *map.get(1));
48+
ASSERT_EQ(1, *map.access(1));
4949
}
5050

5151
TEST(ExpiringWaitFreeHashMap, operator_brackets) {
@@ -54,14 +54,14 @@ TEST(ExpiringWaitFreeHashMap, operator_brackets) {
5454
ASSERT_EQ(1u, map.calc_size());
5555
map[1] = 5;
5656
map[2]++;
57-
ASSERT_EQ(5, *map.get(1));
57+
ASSERT_EQ(5, *map.access(1));
5858
ASSERT_EQ(1, map[2]);
5959
ASSERT_EQ(2u, map.calc_size());
6060
td::Time::jump_in_future(td::Time::now() + 6.0);
6161
map[1] += 1;
6262
td::Time::jump_in_future(td::Time::now() + 6.0);
6363
// item 2 is expired, but item 1 was accessed through operator[] recently
64-
ASSERT_TRUE(map.get(3) == nullptr);
64+
ASSERT_TRUE(map.access(3) == nullptr);
6565
ASSERT_EQ(1u, map.calc_size());
6666
ASSERT_EQ(6, map[1]);
6767
ASSERT_EQ(0, map[2]);
@@ -80,16 +80,16 @@ TEST(ExpiringWaitFreeHashMap, large) {
8080
}
8181
ASSERT_EQ(static_cast<size_t>(count), map.calc_size());
8282
for (int i = 1; i <= count; i++) {
83-
ASSERT_EQ(i, *map.get(i));
83+
ASSERT_EQ(i, *map.access(i));
8484
}
8585
td::Time::jump_in_future(td::Time::now() + 12.0);
86-
ASSERT_TRUE(map.get(count + 1) == nullptr);
86+
ASSERT_TRUE(map.access(count + 1) == nullptr);
8787
ASSERT_EQ(static_cast<size_t>(count - 10), map.calc_size());
8888
while (!map.empty()) {
89-
ASSERT_TRUE(map.get(count + 1) == nullptr);
89+
ASSERT_TRUE(map.access(count + 1) == nullptr);
9090
}
9191
map.set(1, 2);
92-
ASSERT_EQ(2, *map.get(1));
92+
ASSERT_EQ(2, *map.access(1));
9393
}
9494

9595
TEST(ExpiringWaitFreeHashMap, clear) {
@@ -102,29 +102,29 @@ TEST(ExpiringWaitFreeHashMap, clear) {
102102
map.clear();
103103
ASSERT_TRUE(map.empty());
104104
ASSERT_EQ(0u, map.calc_size());
105-
ASSERT_TRUE(map.get(1) == nullptr);
105+
ASSERT_TRUE(map.access(1) == nullptr);
106106
ASSERT_EQ(0u, map.erase(2));
107107

108108
map.set(1, 10);
109109
map[2] = 20;
110-
ASSERT_EQ(10, *map.get(1));
110+
ASSERT_EQ(10, *map.access(1));
111111
ASSERT_EQ(20, map[2]);
112112
ASSERT_EQ(0, map[3]);
113113
ASSERT_EQ(3u, map.calc_size());
114114
td::Time::jump_in_future(td::Time::now() + 6.0);
115-
ASSERT_EQ(10, *map.get(1));
115+
ASSERT_EQ(10, *map.access(1));
116116
td::Time::jump_in_future(td::Time::now() + 6.0);
117117
// only items added after clear are dropped
118-
ASSERT_TRUE(map.get(4) == nullptr);
118+
ASSERT_TRUE(map.access(4) == nullptr);
119119
ASSERT_EQ(1u, map.calc_size());
120-
ASSERT_EQ(10, *map.get(1));
120+
ASSERT_EQ(10, *map.access(1));
121121

122122
map.clear();
123123
map.clear();
124124
ASSERT_TRUE(map.empty());
125125
map.set(5, 50);
126126
ASSERT_EQ(1u, map.calc_size());
127-
ASSERT_EQ(50, *map.get(5));
127+
ASSERT_EQ(50, *map.access(5));
128128
ASSERT_EQ(1u, map.erase(5));
129129
ASSERT_TRUE(map.empty());
130130

@@ -136,14 +136,29 @@ TEST(ExpiringWaitFreeHashMap, clear) {
136136
map.clear();
137137
ASSERT_TRUE(map.empty());
138138
ASSERT_EQ(0u, map.calc_size());
139-
ASSERT_TRUE(map.get(count / 2) == nullptr);
139+
ASSERT_TRUE(map.access(count / 2) == nullptr);
140140
for (int i = 1; i <= count; i++) {
141141
map[i] = -i;
142142
}
143143
ASSERT_EQ(static_cast<size_t>(count), map.calc_size());
144-
ASSERT_EQ(-count / 2, *map.get(count / 2));
144+
ASSERT_EQ(-count / 2, *map.access(count / 2));
145145
map.clear();
146146
map.set(1, 1);
147147
ASSERT_EQ(1u, map.calc_size());
148+
ASSERT_EQ(1, *map.access(1));
149+
}
150+
151+
TEST(ExpiringWaitFreeHashMap, get) {
152+
td::ExpiringWaitFreeHashMap<int, int> map(10.0);
153+
map.set(1, 1);
154+
map.set(2, 2);
148155
ASSERT_EQ(1, *map.get(1));
156+
ASSERT_TRUE(map.get(3) == nullptr);
157+
td::Time::jump_in_future(td::Time::now() + 6.0);
158+
ASSERT_EQ(1, *map.get(1)); // doesn't update access time
159+
ASSERT_EQ(2, *map.access(2)); // updates access time
160+
td::Time::jump_in_future(td::Time::now() + 6.0);
161+
ASSERT_TRUE(map.get(1) == nullptr); // the expired item is dropped
162+
ASSERT_EQ(1u, map.calc_size());
163+
ASSERT_EQ(2, *map.get(2));
149164
}

0 commit comments

Comments
 (0)