Skip to content

Commit 5c6b2fc

Browse files
committed
add benchmarks
1 parent af12af2 commit 5c6b2fc

18 files changed

+4286
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ include(${CMAKE_SOURCE_DIR}/third-party/glog.cmake)
5353
# ------------------------------------------------------------------------------
5454

5555
add_subdirectory(source)
56+
add_subdirectory(benchmarks)
5657

5758
# tests
5859
include(CTest)

benchmarks/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# add_subdirectory(ycsb)

benchmarks/shared/Adapter.hpp

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#pragma once
2+
3+
#include "Exceptions.hpp"
4+
#include "Types.hpp"
5+
6+
#include "KVInterface.hpp"
7+
#include "storage/btree/core/WALMacros.hpp"
8+
9+
#include <cassert>
10+
#include <cstdint>
11+
#include <cstring>
12+
#include <functional>
13+
#include <string>
14+
15+
// Helpers to generate a descriptor that describes which attributes are in-place
16+
// updating in a fixed-size value
17+
#define UpdateDescriptorInit(Name, Count) \
18+
u8 Name##_buffer[sizeof(leanstore::UpdateSameSizeInPlaceDescriptor) + \
19+
(sizeof(leanstore::UpdateSameSizeInPlaceDescriptor::Slot) * \
20+
Count)]; \
21+
auto& Name = *reinterpret_cast<leanstore::UpdateSameSizeInPlaceDescriptor*>( \
22+
Name##_buffer); \
23+
Name.count = Count;
24+
25+
#define UpdateDescriptorFillSlot(Name, Index, Type, Attribute) \
26+
Name.slots[Index].offset = offsetof(Type, Attribute); \
27+
Name.slots[Index].length = sizeof(Type::Attribute);
28+
29+
#define UpdateDescriptorGenerator1(Name, Type, A0) \
30+
UpdateDescriptorInit(Name, 1); \
31+
UpdateDescriptorFillSlot(Name, 0, Type, A0);
32+
33+
#define UpdateDescriptorGenerator2(Name, Type, A0, A1) \
34+
UpdateDescriptorInit(Name, 2); \
35+
UpdateDescriptorFillSlot(Name, 0, Type, A0); \
36+
UpdateDescriptorFillSlot(Name, 1, Type, A1);
37+
38+
#define UpdateDescriptorGenerator3(Name, Type, A0, A1, A2) \
39+
UpdateDescriptorInit(Name, 3); \
40+
UpdateDescriptorFillSlot(Name, 0, Type, A0); \
41+
UpdateDescriptorFillSlot(Name, 1, Type, A1); \
42+
UpdateDescriptorFillSlot(Name, 2, Type, A2);
43+
44+
#define UpdateDescriptorGenerator4(Name, Type, A0, A1, A2, A3) \
45+
UpdateDescriptorInit(Name, 4); \
46+
UpdateDescriptorFillSlot(Name, 0, Type, A0); \
47+
UpdateDescriptorFillSlot(Name, 1, Type, A1); \
48+
UpdateDescriptorFillSlot(Name, 2, Type, A2); \
49+
UpdateDescriptorFillSlot(Name, 3, Type, A3);
50+
51+
// -------------------------------------------------------------------------------------
52+
// Unified interface used by our benchmarks for different storage engines
53+
// including LeanStore
54+
template <class Record> class Adapter {
55+
public:
56+
// Scan in ascending order, scan can fail if it is executed in optimistic mode
57+
// without latching the leaves
58+
virtual void scan(const typename Record::Key& key,
59+
const std::function<bool(const typename Record::Key&,
60+
const Record&)>& found_record_cb,
61+
std::function<void()> reset_if_scan_failed_cb) = 0;
62+
// -------------------------------------------------------------------------------------
63+
virtual void scanDesc(
64+
const typename Record::Key& key,
65+
const std::function<bool(const typename Record::Key&, const Record&)>&
66+
found_record_cb,
67+
std::function<void()> reset_if_scan_failed_cb) = 0;
68+
// -------------------------------------------------------------------------------------
69+
virtual void insert(const typename Record::Key& key,
70+
const Record& record) = 0;
71+
// -------------------------------------------------------------------------------------
72+
virtual void lookup1(const typename Record::Key& key,
73+
const std::function<void(const Record&)>& callback) = 0;
74+
// -------------------------------------------------------------------------------------
75+
virtual void update1(
76+
const typename Record::Key& key,
77+
const std::function<void(Record&)>& update_the_record_in_place_cb,
78+
leanstore::UpdateSameSizeInPlaceDescriptor& update_descriptor) = 0;
79+
// -------------------------------------------------------------------------------------
80+
// Returns false if the record was not found
81+
virtual bool erase(const typename Record::Key& key) = 0;
82+
// -------------------------------------------------------------------------------------
83+
template <class Field>
84+
Field lookupField(const typename Record::Key& key, Field Record::*f) {
85+
UNREACHABLE();
86+
}
87+
};

benchmarks/shared/GenericSchema.hpp

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#pragma once
2+
3+
#include "shared/Types.hpp"
4+
5+
template <typename TableKey, typename TablePayload> struct Relation {
6+
static constexpr int id = 0;
7+
struct Key {
8+
static constexpr int id = 0;
9+
TableKey my_key;
10+
};
11+
TablePayload my_payload;
12+
// -------------------------------------------------------------------------------------
13+
template <class T> static unsigned foldKey(uint8_t* out, const T& key) {
14+
unsigned pos = 0;
15+
pos += fold(out + pos, key.my_key);
16+
return pos;
17+
}
18+
template <class T> static unsigned unfoldKey(const uint8_t* in, T& key) {
19+
unsigned pos = 0;
20+
pos += unfold(in + pos, key.my_key);
21+
return pos;
22+
}
23+
static constexpr unsigned maxFoldLength() {
24+
return 0 + sizeof(Key::my_key);
25+
};
26+
};
27+
// -------------------------------------------------------------------------------------
28+
template <u64 size> struct BytesPayload {
29+
u8 value[size];
30+
BytesPayload() {
31+
}
32+
bool operator==(BytesPayload& other) {
33+
return (std::memcmp(value, other.value, sizeof(value)) == 0);
34+
}
35+
bool operator!=(BytesPayload& other) {
36+
return !(operator==(other));
37+
}
38+
BytesPayload(const BytesPayload& other) {
39+
std::memcpy(value, other.value, sizeof(value));
40+
}
41+
BytesPayload& operator=(const BytesPayload& other) {
42+
std::memcpy(value, other.value, sizeof(value));
43+
return *this;
44+
}
45+
};

benchmarks/shared/LMDBAdapter.hpp

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#pragma once
2+
#include "Adapter.hpp"
3+
#include "Types.hpp"
4+
// -------------------------------------------------------------------------------------
5+
#include "leanstore/Config.hpp"
6+
#include "leanstore/KVInterface.hpp"
7+
#include "leanstore/storage/btree/core/WALMacros.hpp"
8+
#include "leanstore/utils/JumpMU.hpp"
9+
#include "lmdb++.hpp" // Using C++ Wrapper from LMDB
10+
// -------------------------------------------------------------------------------------
11+
#include <cassert>
12+
#include <cstdint>
13+
#include <cstring>
14+
#include <functional>
15+
#include <string>
16+
// -------------------------------------------------------------------------------------
17+
struct LMDB {
18+
lmdb::env env;
19+
lmdb::txn dummy_tx{nullptr};
20+
static thread_local lmdb::txn txn;
21+
22+
LMDB() : env(lmdb::env::create())
23+
{
24+
env.set_max_dbs(100);
25+
// FLAGS_dram_gib is misued here to set the maximum map size for LMDB
26+
env.set_mapsize(FLAGS_dram_gib * 1024UL * 1024UL * 1024UL);
27+
env.open(FLAGS_ssd_path.c_str(), MDB_NOSYNC);
28+
}
29+
// -------------------------------------------------------------------------------------
30+
void startTX(bool read_only = false) { txn = lmdb::txn::begin(env, nullptr, read_only ? MDB_RDONLY : 0); }
31+
// -------------------------------------------------------------------------------------
32+
void commitTX() { txn.commit(); }
33+
// -------------------------------------------------------------------------------------
34+
void abortTX() { txn.abort(); }
35+
// -------------------------------------------------------------------------------------
36+
~LMDB() {}
37+
};
38+
// -------------------------------------------------------------------------------------
39+
template <class Record>
40+
struct LMDBAdapter : public Adapter<Record> {
41+
LMDB& map;
42+
std::string name;
43+
lmdb::dbi dbi;
44+
// -------------------------------------------------------------------------------------
45+
lmdb::txn& hack()
46+
{
47+
map.dummy_tx = lmdb::txn::begin(map.env);
48+
return map.dummy_tx;
49+
}
50+
// -------------------------------------------------------------------------------------
51+
LMDBAdapter(LMDB& map, std::string name) : map(map), name(name), dbi(lmdb::dbi::open(hack(), name.c_str(), MDB_CREATE)) { map.dummy_tx.commit(); }
52+
// -------------------------------------------------------------------------------------
53+
void insert(const typename Record::Key& key, const Record& record) final
54+
{
55+
u8 folded_key[Record::maxFoldLength()];
56+
const u32 folded_key_len = Record::foldKey(folded_key, key);
57+
lmdb::val lmdb_key{folded_key, folded_key_len};
58+
lmdb::val lmdb_payload{const_cast<Record*>(&record), sizeof(record)};
59+
// -------------------------------------------------------------------------------------
60+
if (!dbi.put(map.txn, lmdb_key, lmdb_payload))
61+
throw;
62+
}
63+
// -------------------------------------------------------------------------------------
64+
void lookup1(const typename Record::Key& key, const std::function<void(const Record&)>& fn) final
65+
{
66+
u8 folded_key[Record::maxFoldLength()];
67+
const u32 folded_key_len = Record::foldKey(folded_key, key);
68+
lmdb::val lmdb_key{folded_key, folded_key_len};
69+
lmdb::val lmdb_payload;
70+
// -------------------------------------------------------------------------------------
71+
if (!dbi.get(map.txn, lmdb_key, lmdb_payload))
72+
throw;
73+
Record& record = *reinterpret_cast<Record*>(lmdb_payload.data());
74+
fn(record);
75+
}
76+
// -------------------------------------------------------------------------------------
77+
void update1(const typename Record::Key& key, const std::function<void(Record&)>& fn, leanstore::UpdateSameSizeInPlaceDescriptor&) final
78+
{
79+
Record r;
80+
lookup1(key, [&](const Record& rec) { r = rec; });
81+
fn(r);
82+
insert(key, r);
83+
}
84+
// -------------------------------------------------------------------------------------
85+
bool erase(const typename Record::Key& key) final
86+
{
87+
u8 folded_key[Record::maxFoldLength()];
88+
const u32 folded_key_len = Record::foldKey(folded_key, key);
89+
lmdb::val lmdb_key{folded_key, folded_key_len};
90+
// -------------------------------------------------------------------------------------
91+
if (!dbi.del(map.txn, lmdb_key))
92+
throw;
93+
return true;
94+
}
95+
// -------------------------------------------------------------------------------------
96+
void scan(const typename Record::Key& key, const std::function<bool(const typename Record::Key&, const Record&)>& fn, std::function<void()>) final
97+
{
98+
u8 folded_key[Record::maxFoldLength()];
99+
const u32 folded_key_len = Record::foldKey(folded_key, key);
100+
lmdb::val lmdb_key{folded_key, folded_key_len};
101+
// -------------------------------------------------------------------------------------
102+
lmdb::val lmdb_payload;
103+
lmdb::cursor cursor = lmdb::cursor::open(map.txn, dbi);
104+
if (cursor.get(lmdb_key, lmdb_payload, MDB_SET_RANGE)) {
105+
bool cont;
106+
do {
107+
typename Record::Key s_key;
108+
Record::unfoldKey(reinterpret_cast<const u8*>(lmdb_key.data()), s_key);
109+
Record& s_value = *reinterpret_cast<Record*>(lmdb_payload.data());
110+
cont = fn(s_key, s_value);
111+
} while (cont && cursor.get(lmdb_key, lmdb_payload, MDB_NEXT));
112+
}
113+
}
114+
// -------------------------------------------------------------------------------------
115+
void scanDesc(const typename Record::Key& key,
116+
const std::function<bool(const typename Record::Key&, const Record&)>& fn,
117+
std::function<void()>) final
118+
{
119+
u8 folded_key[Record::maxFoldLength()];
120+
const u32 folded_key_len = Record::foldKey(folded_key, key);
121+
lmdb::val lmdb_key{folded_key, folded_key_len};
122+
// -------------------------------------------------------------------------------------
123+
lmdb::val lmdb_payload;
124+
lmdb::cursor cursor = lmdb::cursor::open(map.txn, dbi);
125+
if (!cursor.get(lmdb_key, lmdb_payload, MDB_SET_RANGE)) {
126+
if (!cursor.get(lmdb_key, lmdb_payload, MDB_LAST)) {
127+
return;
128+
}
129+
}
130+
while (true) {
131+
std::basic_string_view<u8> upper(folded_key, folded_key_len);
132+
std::basic_string_view<u8> current(reinterpret_cast<u8*>(lmdb_key.data()), lmdb_key.size());
133+
if (current > upper) {
134+
if (cursor.get(lmdb_key, lmdb_payload, MDB_PREV)) {
135+
continue;
136+
} else {
137+
return;
138+
}
139+
} else {
140+
break;
141+
}
142+
}
143+
bool cont;
144+
do {
145+
typename Record::Key s_key;
146+
Record::unfoldKey(reinterpret_cast<const u8*>(lmdb_key.data()), s_key);
147+
Record& s_value = *reinterpret_cast<Record*>(lmdb_payload.data());
148+
cont = fn(s_key, s_value);
149+
} while (cont && cursor.get(lmdb_key, lmdb_payload, MDB_PREV));
150+
}
151+
// -------------------------------------------------------------------------------------
152+
template <class Field>
153+
auto lookupField(const typename Record::Key& key, Field f)
154+
{
155+
u8 folded_key[Record::maxFoldLength()];
156+
const u32 folded_key_len = Record::foldKey(folded_key, key);
157+
lmdb::val lmdb_key{folded_key, folded_key_len};
158+
lmdb::val lmdb_payload;
159+
// -------------------------------------------------------------------------------------
160+
if (!dbi.get(map.txn, lmdb_key, lmdb_payload))
161+
throw;
162+
Record& record = *reinterpret_cast<Record*>(lmdb_payload.data());
163+
auto ret = record.*f;
164+
return ret;
165+
}
166+
// -------------------------------------------------------------------------------------
167+
uint64_t count()
168+
{
169+
u8 folded_key[Record::maxFoldLength()];
170+
const u32 folded_key_len = Record::foldKey(folded_key, 0);
171+
lmdb::val lmdb_key{folded_key, folded_key_len};
172+
lmdb::cursor cursor = lmdb::cursor::open(map.txn, dbi);
173+
lmdb::val lmdb_payload;
174+
// -------------------------------------------------------------------------------------
175+
uint64_t count = 0;
176+
if (cursor.get(lmdb_key, lmdb_payload, MDB_SET_RANGE)) {
177+
do {
178+
count++;
179+
} while (cursor.get(lmdb_key, lmdb_payload, MDB_NEXT));
180+
}
181+
return count;
182+
}
183+
};

0 commit comments

Comments
 (0)