This repository has been archived by the owner on Oct 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5687 from ethereum/tq-maxdropped
Enforce 1024 max dropped transactions in the transaction queue
- Loading branch information
Showing
7 changed files
with
234 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Aleth: Ethereum C++ client, tools and libraries. | ||
// Copyright 2019 Aleth Authors. | ||
// Licensed under the GNU General Public License, Version 3. | ||
|
||
#pragma once | ||
|
||
#include <list> | ||
#include <unordered_map> | ||
|
||
namespace dev | ||
{ | ||
template <class Key, class Value> | ||
class LruCache | ||
{ | ||
using key_type = Key; | ||
using value_type = Value; | ||
using list_type = std::list<std::pair<key_type, value_type>>; | ||
using map_type = std::unordered_map<key_type, typename list_type::const_iterator>; | ||
|
||
public: | ||
explicit LruCache(size_t _capacity) : m_capacity(_capacity) {} | ||
|
||
size_t insert(key_type const& _key, value_type const& _val) | ||
{ | ||
auto const cIter = m_index.find(_key); | ||
if (cIter == m_index.cend()) | ||
{ | ||
if (m_index.size() == m_capacity) | ||
{ | ||
m_index.erase(m_data.back().first); | ||
m_data.pop_back(); | ||
} | ||
m_data.push_front({_key, _val}); | ||
m_index[_key] = m_data.begin(); | ||
} | ||
else | ||
m_data.splice(m_data.begin(), m_data, cIter->second); | ||
|
||
return m_index.size(); | ||
} | ||
|
||
size_t remove(key_type const& _key) | ||
{ | ||
auto const cIter = m_index.find(_key); | ||
if (cIter != m_index.cend()) | ||
{ | ||
m_data.erase(cIter->second); | ||
m_index.erase(cIter); | ||
} | ||
|
||
return m_index.size(); | ||
} | ||
|
||
bool touch(key_type const& _key) | ||
{ | ||
auto const cIter = m_index.find(_key); | ||
if (cIter != m_index.cend()) | ||
{ | ||
m_data.splice(m_data.begin(), m_data, cIter->second); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
bool contains(key_type const& _key) const { return m_index.find(_key) != m_index.cend(); } | ||
|
||
bool contains(key_type const& _key, value_type const& _value) const | ||
{ | ||
auto const cIter = m_index.find(_key); | ||
return cIter != m_index.cend() && (*(cIter->second)).second == _value; | ||
} | ||
|
||
bool empty() const noexcept { return m_index.empty(); } | ||
|
||
size_t size() const noexcept { return m_index.size(); } | ||
|
||
size_t capacity() const noexcept { return m_capacity; } | ||
|
||
void clear() noexcept | ||
{ | ||
m_index.clear(); | ||
m_data.clear(); | ||
} | ||
|
||
// Expose data iterator for testing purposes | ||
typename list_type::const_iterator cbegin() const noexcept { return m_data.cbegin(); } | ||
typename list_type::iterator begin() noexcept { return m_data.begin(); } | ||
typename list_type::const_iterator cend() const noexcept { return m_data.cend(); } | ||
typename list_type::iterator end() noexcept { return m_data.end(); } | ||
|
||
private: | ||
list_type m_data; | ||
map_type m_index; | ||
size_t m_capacity; | ||
}; | ||
} // namespace dev |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Aleth: Ethereum C++ client, tools and libraries. | ||
// Copyright 2019 Aleth Authors. | ||
// Licensed under the GNU General Public License, Version 3. | ||
|
||
#include <libdevcore/LruCache.h> | ||
#include <test/tools/libtestutils/Common.h> | ||
#include <gtest/gtest.h> | ||
|
||
using namespace std; | ||
using namespace dev; | ||
using namespace dev::test; | ||
|
||
namespace | ||
{ | ||
using LRU = LruCache<int, int>; | ||
using PAIR = pair<int, int>; | ||
using VEC = vector<PAIR>; | ||
|
||
constexpr size_t c_capacity = 10; | ||
|
||
mt19937_64 g_randomGenerator(random_device{}()); | ||
|
||
int randomNumber(int _min = INT_MIN, int _max = INT_MAX) | ||
{ | ||
return std::uniform_int_distribution<int>{_min, _max}(g_randomGenerator); | ||
} | ||
|
||
VEC Populate(LRU& _lruCache, size_t _count) | ||
{ | ||
VEC ret; | ||
for (size_t i = 0; i < _count; i++) | ||
{ | ||
auto const item = PAIR{randomNumber(), randomNumber()}; | ||
ret.push_back(item); | ||
_lruCache.insert(item.first, item.second); | ||
} | ||
reverse(ret.begin(), ret.end()); | ||
|
||
return ret; | ||
} | ||
|
||
void VerifyEquals(LRU& _lruCache, VEC& _data) | ||
{ | ||
EXPECT_EQ(_lruCache.size(), _data.size()); | ||
size_t i = 0; | ||
auto iter = _lruCache.begin(); | ||
while (iter != _lruCache.cend() && i < _data.size()) | ||
{ | ||
EXPECT_EQ(*iter, _data[i]); | ||
iter++; | ||
i++; | ||
} | ||
} | ||
} // namespace | ||
|
||
TEST(LruCache, BasicOperations) | ||
{ | ||
LRU lruCache{c_capacity}; | ||
EXPECT_EQ(lruCache.capacity(), c_capacity); | ||
EXPECT_TRUE(lruCache.empty()); | ||
|
||
// Populate and verify | ||
VEC testData = Populate(lruCache, lruCache.capacity()); | ||
VerifyEquals(lruCache, testData); | ||
|
||
// Reverse order and verify | ||
for (size_t i = 0; i < testData.size(); i++) | ||
lruCache.touch(testData[i].first); | ||
reverse(testData.begin(), testData.end()); | ||
VerifyEquals(lruCache, testData); | ||
|
||
// Remove elements and verify | ||
auto size = lruCache.size(); | ||
for (PAIR item : testData) | ||
{ | ||
lruCache.remove(item.first); | ||
EXPECT_FALSE(lruCache.contains(item.first)); | ||
EXPECT_EQ(lruCache.size(), --size); | ||
} | ||
} | ||
|
||
TEST(LruCache, AdvancedOperations) | ||
{ | ||
LRU lruCache{c_capacity}; | ||
VEC testData = Populate(lruCache, lruCache.capacity()); | ||
VerifyEquals(lruCache, testData); | ||
testData = Populate(lruCache, lruCache.capacity()); | ||
VerifyEquals(lruCache, testData); | ||
lruCache.clear(); | ||
EXPECT_TRUE(lruCache.empty()); | ||
EXPECT_EQ(lruCache.capacity(), c_capacity); | ||
} | ||
|
||
TEST(LruCache, Constructors) | ||
{ | ||
LRU lruCache{c_capacity}; | ||
VEC testData = Populate(lruCache, lruCache.capacity()); | ||
VerifyEquals(lruCache, testData); | ||
|
||
LRU lruCacheCopy{lruCache}; | ||
VerifyEquals(lruCacheCopy, testData); | ||
EXPECT_EQ(lruCache.capacity(), lruCacheCopy.capacity()); | ||
|
||
LRU lruCacheMove{move(lruCache)}; | ||
VerifyEquals(lruCacheMove, testData); | ||
EXPECT_TRUE(lruCache.empty()); | ||
EXPECT_EQ(lruCache.capacity(), c_capacity); | ||
} |