ClickHouse/src/Coordination/SnapshotableHashTable.h

198 lines
4.5 KiB
C++
Raw Normal View History

2021-02-25 14:23:12 +00:00
#pragma once
#include <common/StringRef.h>
2021-02-25 19:52:22 +00:00
#include <unordered_map>
#include <list>
2021-02-26 13:53:34 +00:00
#include <atomic>
2021-02-25 14:23:12 +00:00
namespace DB
{
2021-02-25 19:52:22 +00:00
template<typename V>
struct ListNode
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
std::string key;
V value;
2021-02-26 13:56:57 +00:00
bool active_in_map;
2021-02-25 14:23:12 +00:00
};
2021-02-25 19:52:22 +00:00
template <class V>
class SnapshotableHashTable
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
private:
2021-02-25 14:23:12 +00:00
2021-02-25 19:52:22 +00:00
using ListElem = ListNode<V>;
using List = std::list<ListElem>;
using IndexMap = std::unordered_map<StringRef, typename List::iterator, StringRefHash>;
2021-02-25 14:23:12 +00:00
2021-02-25 19:52:22 +00:00
List list;
IndexMap map;
2021-03-03 12:21:21 +00:00
bool snapshot_mode{false};
2021-02-25 14:23:12 +00:00
2021-02-25 19:52:22 +00:00
public:
2021-02-25 14:23:12 +00:00
using iterator = typename List::iterator;
using const_iterator = typename List::const_iterator;
using reverse_iterator = typename List::reverse_iterator;
using const_reverse_iterator = typename List::const_reverse_iterator;
2021-02-25 19:52:22 +00:00
using ValueUpdater = std::function<void(V & value)>;
2021-02-25 14:23:12 +00:00
2021-02-26 13:53:34 +00:00
bool insert(const std::string & key, const V & value)
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
auto it = map.find(key);
if (it == map.end())
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
ListElem elem{key, value, true};
auto itr = list.insert(list.end(), elem);
map.emplace(itr->key, itr);
return true;
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
return false;
}
2021-03-01 13:33:34 +00:00
void insertOrReplace(const std::string & key, const V & value)
{
auto it = map.find(key);
if (it == map.end())
{
ListElem elem{key, value, true};
auto itr = list.insert(list.end(), elem);
map.emplace(itr->key, itr);
}
else
{
auto list_itr = it->second;
if (snapshot_mode)
{
ListElem elem{key, value, true};
list_itr->active_in_map = false;
auto new_list_itr = list.insert(list.end(), elem);
2021-03-02 12:34:18 +00:00
map.erase(it);
map.emplace(new_list_itr->key, new_list_itr);
2021-03-01 13:33:34 +00:00
}
else
{
list_itr->value = value;
}
}
}
2021-02-26 13:53:34 +00:00
bool erase(const std::string & key)
{
auto it = map.find(key);
if (it == map.end())
return false;
auto list_itr = it->second;
if (snapshot_mode)
{
list_itr->active_in_map = false;
map.erase(it);
}
2021-02-25 14:23:12 +00:00
else
{
2021-02-26 13:53:34 +00:00
map.erase(it);
list.erase(list_itr);
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
return true;
2021-02-25 14:23:12 +00:00
}
2021-02-25 19:52:22 +00:00
bool contains(const std::string & key) const
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
return map.find(key) != map.end();
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
const_iterator updateValue(const std::string & key, ValueUpdater updater)
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
auto it = map.find(key);
assert(it != map.end());
if (snapshot_mode)
{
auto list_itr = it->second;
auto elem_copy = *(list_itr);
2021-02-26 13:53:34 +00:00
list_itr->active_in_map = false;
2021-03-03 12:21:21 +00:00
map.erase(it);
2021-02-25 19:52:22 +00:00
updater(elem_copy.value);
auto itr = list.insert(list.end(), elem_copy);
2021-03-02 12:34:18 +00:00
map.emplace(itr->key, itr);
2021-02-26 13:53:34 +00:00
return itr;
2021-02-25 19:52:22 +00:00
}
else
{
auto list_itr = it->second;
updater(list_itr->value);
2021-02-26 13:53:34 +00:00
return list_itr;
2021-02-25 19:52:22 +00:00
}
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
const_iterator find(const std::string & key) const
{
auto map_it = map.find(key);
if (map_it != map.end())
return map_it->second;
return list.end();
}
2021-02-25 19:52:22 +00:00
const V & getValue(const std::string & key) const
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
auto it = map.find(key);
assert(it != map.end());
return it->second->value;
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
void clearOutdatedNodes()
{
auto start = list.begin();
auto end = list.end();
for (auto itr = start; itr != end;)
{
if (!itr->active_in_map)
itr = list.erase(itr);
else
itr++;
}
}
2021-02-25 19:52:22 +00:00
void clear()
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
list.clear();
map.clear();
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
void enableSnapshotMode()
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
snapshot_mode = true;
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
void disableSnapshotMode()
2021-02-25 14:23:12 +00:00
{
2021-02-25 19:52:22 +00:00
snapshot_mode = false;
2021-02-25 14:23:12 +00:00
}
2021-02-26 13:53:34 +00:00
size_t size() const
{
return map.size();
}
size_t snapshotSize() const
{
return list.size();
}
2021-02-25 14:23:12 +00:00
iterator begin() { return list.begin(); }
const_iterator begin() const { return list.cbegin(); }
iterator end() { return list.end(); }
const_iterator end() const { return list.cend(); }
reverse_iterator rbegin() { return list.rbegin(); }
const_reverse_iterator rbegin() const { return list.crbegin(); }
reverse_iterator rend() { return list.rend(); }
const_reverse_iterator rend() const { return list.crend(); }
};
}