-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathStoreBenchmarkBase.cs
More file actions
136 lines (113 loc) · 4.01 KB
/
Copy pathStoreBenchmarkBase.cs
File metadata and controls
136 lines (113 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System.Buffers.Binary;
using System.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Jobs;
using CsSqlite;
using RocksDbSharp;
namespace DryDB.Benchmark;
class BenchmarkConfig : ManualConfig
{
public BenchmarkConfig()
{
AddDiagnoser(MemoryDiagnoser.Default);
AddJob(Job.ShortRun
.WithWarmupCount(10)
.WithIterationCount(10)
);
}
}
/// <summary>
/// Builds the same 10k-row dataset in SQLite (CsSqlite), DryDB and RocksDB.
/// </summary>
public abstract class StoreBenchmarkBase
{
protected const int N = 10000;
protected ReadOnlyDatabase database = default!;
// sqlite: as-is defaults (command prepared per query)
protected SqliteConnection cssqliteConnection = default!;
// sqlite: fair read-only setup (immutable=1, prepared statements reused)
protected SqliteConnection cssqliteImmutableConnection = default!;
protected RocksDb rocksDb = default!;
DirectoryInfo directory = default!;
[GlobalSetup]
public async Task SetupAsync()
{
directory = Directory.CreateTempSubdirectory("drydb_benchmarks");
var sqlitePath = Path.Combine(directory.FullName, "bench.sqlite");
var drydbPath = Path.Combine(directory.FullName, "bench.drydb");
var rocksdbPath = Path.Combine(directory.FullName, "bench.rocksdb");
// Setup sqlite
using (var sqlite = new SqliteConnection(sqlitePath))
{
sqlite.Open();
sqlite.ExecuteNonQuery("DROP TABLE IF EXISTS items;");
sqlite.ExecuteNonQuery("PRAGMA page_size = 4096;");
sqlite.ExecuteNonQuery(
"""
CREATE TABLE IF NOT EXISTS items (
id INTEGER NOT NULL PRIMARY KEY,
data TEXT NOT NULL
);
""");
sqlite.ExecuteNonQuery("BEGIN TRANSACTION;");
for (var i = 0; i < N; i++)
{
sqlite.ExecuteNonQuery(
$"""
INSERT INTO items (id, data) VALUES ({i}, 'val{i:D10}');
""");
}
sqlite.ExecuteNonQuery("COMMIT;");
}
// Setup DryDB
using (var builder = new DatabaseBuilder
{
PageSize = 4096,
})
{
var tableBuilder = builder.CreateTable("items", KeyEncoding.Int64LittleEndian);
for (var i = 0; i < N; i++)
{
tableBuilder.Append(i, Encoding.UTF8.GetBytes($"val{i:D10}"));
}
await builder.BuildToFileAsync(drydbPath);
}
// Setup RocksDB (big-endian keys so that the default bytewise comparator
// sorts them numerically, which range scans rely on)
var rocksDbOptions = new DbOptions().SetCreateIfMissing(true);
using (var db = RocksDb.Open(rocksDbOptions, rocksdbPath))
{
var keyBuffer = new byte[sizeof(long)];
for (var i = 0; i < N; i++)
{
BinaryPrimitives.WriteInt64BigEndian(keyBuffer, i);
db.Put(keyBuffer, Encoding.UTF8.GetBytes($"val{i:D10}"));
}
}
database = await ReadOnlyDatabase.OpenFileAsync(drydbPath, new DatabaseLoadOptions
{
});
cssqliteConnection = new SqliteConnection(sqlitePath);
cssqliteImmutableConnection = new SqliteConnection($"file:{sqlitePath}?immutable=1");
rocksDb = RocksDb.OpenReadOnly(rocksDbOptions, rocksdbPath, false);
OnSetup();
}
[GlobalCleanup]
public void Cleanup()
{
OnCleanup();
cssqliteConnection.Dispose();
cssqliteImmutableConnection.Dispose();
rocksDb.Dispose();
database.Dispose();
try
{
directory.Delete(true);
}
catch (DirectoryNotFoundException) { }
}
protected virtual void OnSetup() { }
protected virtual void OnCleanup() { }
}