Skip to content

Commit 2e53589

Browse files
committed
Add monotonicity
1 parent 1d8653f commit 2e53589

File tree

8 files changed

+335
-328
lines changed

8 files changed

+335
-328
lines changed

CMakeLists.txt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,48 @@ add_executable(speed_test speed_test.cpp
3030
vcpkg.json
3131
memento/memento.h
3232
memento/mementoengine.h
33-
memento/mementoneengine.h
3433
anchor/AnchorHashQre.cpp anchor/AnchorHashQre.hpp anchor/misc/crc32c_sse42_u64.h
3534
anchor/anchorengine.h
3635
memento/mashtable.h
3736
jump/jumpengine.h
3837
power/powerengine.h
39-
memento/mementoneshortcutengine.h
4038
)
4139

4240
add_executable(balance balance.cpp
4341
vcpkg.json
4442
memento/memento.h
4543
memento/mementoengine.h
46-
memento/mementoneengine.h
4744
anchor/AnchorHashQre.cpp anchor/AnchorHashQre.hpp anchor/misc/crc32c_sse42_u64.h
4845
anchor/anchorengine.h
4946
memento/mashtable.h
5047
jump/jumpengine.h
5148
power/powerengine.h
52-
memento/mementoneshortcutengine.h
49+
)
50+
51+
add_executable(monotonicity monotonicity.cpp
52+
vcpkg.json
53+
memento/memento.h
54+
memento/mementoengine.h
55+
anchor/AnchorHashQre.cpp anchor/AnchorHashQre.hpp anchor/misc/crc32c_sse42_u64.h
56+
anchor/anchorengine.h
57+
memento/mashtable.h
58+
jump/jumpengine.h
59+
power/powerengine.h
5360
)
5461

5562
add_executable(mashtable_test mashtable_test.cpp memento/mashtable.h)
5663

5764
if(WITH_PCG32)
5865
target_include_directories(speed_test PRIVATE ${PCG_INCLUDE_DIRS})
5966
target_include_directories(balance PRIVATE ${PCG_INCLUDE_DIRS})
67+
target_include_directories(monotonicity PRIVATE ${PCG_INCLUDE_DIRS})
6068
endif()
6169
target_include_directories(speed_test PRIVATE ${GTL_INCLUDE_DIRS})
6270
target_include_directories(balance PRIVATE ${GTL_INCLUDE_DIRS})
71+
target_include_directories(monotonicity PRIVATE ${GTL_INCLUDE_DIRS})
6372
target_link_libraries(speed_test PRIVATE xxHash::xxhash fmt::fmt cxxopts::cxxopts)
6473
target_link_libraries(balance PRIVATE xxHash::xxhash fmt::fmt cxxopts::cxxopts)
74+
target_link_libraries(monotonicity PRIVATE xxHash::xxhash fmt::fmt cxxopts::cxxopts)
6575
include(GNUInstallDirs)
6676
install(TARGETS speed_test
6777
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -72,3 +82,8 @@ install(TARGETS balance
7282
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
7383
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
7484
)
85+
86+
install(TARGETS monotonicity
87+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
88+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
89+
)

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ This project collects C++ implementations and benchmarking tools of some of the
44
The implemented algorithms are:
55
* [2014] __jump hash__ by [Lamping and Veach](https://arxiv.org/pdf/1406.2294.pdf)
66
* [2020] __anchor hash__ by [Gal Mendelson et al.](https://arxiv.org/pdf/1812.09674.pdf), using the implementation found on [Github](https://github.com/anchorhash/cpp-anchorhash)
7+
* [2023] __power consistent hash__ by [Eric Leu](https://arxiv.org/pdf/2307.12448.pdf)
78
* [2023] __memento hash__ by [M. Coluzzi et al.](https://arxiv.org/pdf/2306.09783.pdf)
89

910
## Benchmarks
1011

11-
The project includes a two benchmarking tools **speed_test** and **balance**, derived from the same tools provided by [Anchorhash](https://github.com/anchorhash/cpp-anchorhash)
12+
The project includes three benchmarking tools **speed_test**, **balance**, and **monotonicity** derived from the same tools provided by [Anchorhash](https://github.com/anchorhash/cpp-anchorhash)
1213

1314
**speed_test** also records **heap allocations** and the maximum allocated heap space.
1415

@@ -41,7 +42,7 @@ The **speed_test** benchmark performs several random key lookups, the syntax is:
4142
./speed_test Algorithm AnchorSet WorkingSet NumRemovals Numkeys ResFilename
4243
```
4344
where
44-
* **Algorithm** can be *memento* (for MementoHash using *boost::unordered_flat_map* for the removal set), *mementoboost* (for MementoHash using *boost::unordered_map* for the removal set), *mementostd* (for MementoHash using *std::unordered_map* for the removal set), *mementomash* (for MementoHash using a hash table similar to Java's HashMap), *anchor* (for AnchorHash), *mementogtl* (for Memento with gtl hash map), *jump* (for JumpHash)
45+
* **Algorithm** can be *memento* (for MementoHash using *boost::unordered_flat_map* for the removal set), *mementoboost* (for MementoHash using *boost::unordered_map* for the removal set), *mementostd* (for MementoHash using *std::unordered_map* for the removal set), *mementomash* (for MementoHash using a hash table similar to Java's HashMap), *anchor* (for AnchorHash), *mementogtl* (for Memento with gtl hash map), *jump* (for JumpHash), *power* (for Power Consistent Hashing)
4546
* **AnchorSet** is the size of the Anchor set (**a**): this parameter is used only by *anchor* but must be set to a value *at least equal to WorkingSet* even with *MementoHash*;
4647
* **WorkingSet** is the size of the initial Working set (**w**);
4748
* **NumRemovals** is the number of nodes that should be removed (randomly, except for *Jump*) before starting the benchmark;
@@ -65,6 +66,17 @@ The **balance** benchmark performs a balance test and accepts the same parameter
6566
Algorithm: memento, AnchorSet: 1000000, WorkingSet: 1000000, NumRemovals: 20000, NumKeys: 1000000, ResFileName: memento.txt
6667
Memento<boost::unordered_flat_map>: LB is 8.82
6768
```
69+
The **monotonicity** benchmark performs a monotonicity test and accepts the same parameters as **speed_test**. Example:
70+
71+
```bash
72+
./monotonicity memento 1000000 1000000 1000 1000000 memento.txt
73+
Algorithm: memento, AnchorSet: 1000000, WorkingSet: 1000000, NumRemovals: 1000, NumKeys: 1000000, ResFileName: memento.txt
74+
Done determining initial assignment of 1000000 unique keys
75+
Removed node 424868
76+
Memento<boost::unordered_flat_map>: after removal misplaced keys are 0% (0 keys out of 1000000)
77+
Added node 424868
78+
Memento<boost::unordered_flat_map>: after adding back misplaced keys are 0% (0 keys out of 1000000)
79+
```
6880

6981
## Java implementation
7082
For a Java implementation of these and additional algorithms please refer to [this repository](https://github.com/SUPSI-DTI-ISIN/java-consistent-hashing-algorithms)

balance.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
#include "memento/mementoengine.h"
2727
#include "jump/jumpengine.h"
2828
#include "power/powerengine.h"
29-
#include "memento/mementoneengine.h"
30-
#include "memento/mementoneshortcutengine.h"
3129
#include <fmt/core.h>
3230
#include <fstream>
3331
#include <unordered_map>
@@ -131,7 +129,7 @@ int main(int argc, char *argv[]) {
131129
cxxopts::Options options("speed_test", "MementoHash vs AnchorHash benchmark");
132130
options.add_options()(
133131
"Algorithm",
134-
"Algorithm (null|baseline|anchor|memento|mementoboost|mementomash|mementostd|mementogtl|jump|power|mementone)",
132+
"Algorithm (null|baseline|anchor|memento|mementoboost|mementomash|mementostd|mementogtl|jump|power)",
135133
cxxopts::value<std::string>())(
136134
"AnchorSet", "Size of the AnchorSet (ignored by Memento)",
137135
cxxopts::value<int>())("WorkingSet", "Size of the WorkingSet",
@@ -214,14 +212,6 @@ int main(int argc, char *argv[]) {
214212
return bench<PowerEngine>("PowerEngine", filename,
215213
anchor_set, working_set,
216214
num_removals, num_keys);
217-
} else if (algorithm == "mementone") {
218-
return bench<MementoneEngine<boost::unordered_flat_map>>(
219-
"Mementone<boost::unordered_flat_map>", filename, anchor_set, working_set,
220-
num_removals, num_keys);
221-
} else if (algorithm == "mementoneshortcut") {
222-
return bench<MementoneShortcutEngine>(
223-
"MementoneShortcutEngine", filename, anchor_set, working_set,
224-
num_removals, num_keys);
225215
} else {
226216
fmt::println("Unknown algorithm {}", algorithm);
227217
return 2;

memento/mashtable.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@ template <Integral K, typename V> class MashTable final {
2727
static constexpr uint32_t MIN_TABLE_SIZE = 1 << 4;
2828
static constexpr uint32_t MAX_TABLE_SIZE = 1 << 30;
2929

30-
struct Entry final {
30+
struct Item final {
3131
K m_key;
3232
V m_value;
33-
Entry *m_next;
33+
Item *m_next;
3434

35-
Entry(K key, V value, Entry *next = nullptr)
35+
Item(K key, V value, Item *next = nullptr)
3636
: m_key{key}, m_value{value}, m_next{next} {}
3737
};
3838

39-
Entry **m_table;
39+
Item **m_table;
4040
uint32_t m_length;
4141
uint32_t m_size;
4242

43-
void add(Entry *entry, Entry **table, uint32_t table_length) {
43+
void add(Item *entry, Item **table, uint32_t table_length) {
4444
auto kint{static_cast<unsigned int>(entry->m_key)};
4545
unsigned int hash = kint ^ kint >> 16;
4646
unsigned int index = (table_length - 1) & hash;
@@ -53,7 +53,7 @@ template <Integral K, typename V> class MashTable final {
5353
return;
5454
if (newTableSize > m_length && m_length >= MAX_TABLE_SIZE)
5555
return;
56-
auto newTable{new Entry *[newTableSize]()};
56+
auto newTable{new Item *[newTableSize]()};
5757
for (unsigned int i{0}; i < m_length; ++i) {
5858
auto entry{m_table[i]};
5959
while (entry) {
@@ -78,7 +78,7 @@ template <Integral K, typename V> class MashTable final {
7878
if (!entry) {
7979
return;
8080
}
81-
Entry *prev{nullptr};
81+
Item *prev{nullptr};
8282
while (entry && entry->m_key != key) {
8383
prev = entry;
8484
entry = entry->m_next;
@@ -96,7 +96,7 @@ template <Integral K, typename V> class MashTable final {
9696
delete entry;
9797
}
9898

99-
void doFree(Entry** t, uint32_t s) {
99+
void doFree(Item** t, uint32_t s) {
100100
for(unsigned int i{0}; i<s; ++i) {
101101
auto e{t[i]};
102102
while(e) {
@@ -111,11 +111,11 @@ template <Integral K, typename V> class MashTable final {
111111
public:
112112
struct iterator final {
113113
iterator() : m_pair{nullptr, V()} {}
114-
iterator(Entry *e) : m_pair{e, e->m_value} {}
115-
std::pair<Entry *, V> m_pair;
114+
iterator(Item *e) : m_pair{e, e->m_value} {}
115+
std::pair<Item *, V> m_pair;
116116

117-
const std::pair<Entry *, V> &operator*() const noexcept { return m_pair; }
118-
std::pair<Entry *, V> *operator->() noexcept { return &m_pair; }
117+
const std::pair<Item *, V> &operator*() const noexcept { return m_pair; }
118+
std::pair<Item *, V> *operator->() noexcept { return &m_pair; }
119119
bool operator==(const iterator &o) const noexcept {
120120
return m_pair.first == o.m_pair.first;
121121
}
@@ -125,7 +125,7 @@ template <Integral K, typename V> class MashTable final {
125125
};
126126

127127
MashTable()
128-
: m_table{new Entry *[MIN_TABLE_SIZE]()}, m_length{MIN_TABLE_SIZE},
128+
: m_table{new Item *[MIN_TABLE_SIZE]()}, m_length{MIN_TABLE_SIZE},
129129
m_size{0} {}
130130

131131
~MashTable() noexcept {
@@ -136,7 +136,7 @@ template <Integral K, typename V> class MashTable final {
136136
MashTable& operator=(const MashTable&) = delete;
137137

138138
int emplace(const K &key, V &&value) noexcept {
139-
Entry *entry{new Entry{key, std::move(value)}};
139+
Item *entry{new Item{key, std::move(value)}};
140140
add(entry, m_table, m_length);
141141
++m_size;
142142
if (m_size > capacity()) {
@@ -164,8 +164,8 @@ template <Integral K, typename V> class MashTable final {
164164
}
165165

166166
void erase(const iterator &it) {
167-
if (it.e) {
168-
remove(it.e->m_key);
167+
if (it.m_pair.first) {
168+
remove(it.m_pair.first->m_key);
169169
--m_size;
170170
if (m_size <= capacity() >> 2)
171171
resizeTable(m_length >> 1);

memento/memento.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ class Memento final
7878
return bucket + 1;
7979
}
8080
auto e = m_table.find(bucket);
81+
auto ret{e->second.prevRemoved};
8182
m_table.erase(e);
82-
return e->second.prevRemoved;
83+
return ret;
8384
}
8485

8586
/**

0 commit comments

Comments
 (0)