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(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
}
|