From 7444ef81cf54dd6d272bdc13113e2a11f71a114a Mon Sep 17 00:00:00 2001 From: Ahmed Yasin Koculu Date: Sun, 24 Jul 2022 06:07:18 +0200 Subject: [PATCH] Adds transactional benchmarks. --- README.md | 4 +- src/Playground/Benchmark/BenchmarkGroups.cs | 85 ++++++++++++++++----- src/Playground/Benchmark/ZoneTree1.cs | 67 ++++++++++++---- src/Playground/Benchmark/ZoneTree2.cs | 64 ++++++++++++---- src/Playground/Benchmark/ZoneTree3.cs | 85 +++++++++++++++++++++ src/Playground/Program.cs | 2 +- src/Playground/Test1.cs | 4 +- src/ZoneTree/Directory.Build.props | 4 +- 8 files changed, 261 insertions(+), 54 deletions(-) create mode 100644 src/Playground/Benchmark/ZoneTree3.cs diff --git a/README.md b/README.md index 07418d6..8bd2977 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ LSM Tree (Log-structured merge-tree) is the most popular data structure and it i | int-int tree lazy WAL | 1198 ms | 2379 ms | 3831 ms | 15338 ms | | string-string tree immediate WAL | 7872 ms | 16065 ms | 24220 ms | 90901 ms | | string-string tree lazy WAL | 2556 ms | 5240 ms | 7934 ms | 29815 ms | -| RocksDb string-string | 8215 ms | 16146 ms | 23760 ms | 61547 ms | +| RocksDb string-string | 8215 ms | 16146 ms | 23760 ms | 72491 ms | ### Environment: ``` @@ -201,7 +201,7 @@ ZoneTree supports 3 way of doing transactions. The following sample shows how to do the transactions with ZoneTree Fluent Transaction API. ```c# - using var zoneTree = new ZoneTreeFactory() +using var zoneTree = new ZoneTreeFactory() // Additional stuff goes here .OpenOrCreateTransactional(); using var transaction = diff --git a/src/Playground/Benchmark/BenchmarkGroups.cs b/src/Playground/Benchmark/BenchmarkGroups.cs index 683daa0..9a8d374 100644 --- a/src/Playground/Benchmark/BenchmarkGroups.cs +++ b/src/Playground/Benchmark/BenchmarkGroups.cs @@ -4,24 +4,75 @@ namespace Playground.Benchmark; public static class BenchmarkGroups { - public static void InsertBenchmark() + public static void InsertBenchmark1() { - ZoneTree1.TestIntTree(WriteAheadLogMode.Immediate, 1_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Immediate, 2_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Immediate, 3_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Immediate, 10_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Lazy, 1_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Lazy, 2_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Lazy, 3_000_000); - ZoneTree1.TestIntTree(WriteAheadLogMode.Lazy, 10_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 1_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 2_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 3_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 10_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 1_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 2_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 3_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 10_000_000); + } + + public static void InsertBenchmark2() + { + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 1_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 2_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 3_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 10_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 1_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 2_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 3_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 10_000_000); + } + + public static void InsertBenchmark3() + { + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Immediate, 1_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Immediate, 2_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Immediate, 3_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Immediate, 10_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Lazy, 1_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Lazy, 2_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Lazy, 3_000_000); + ZoneTree3.TestInsertTransactionIntTree(WriteAheadLogMode.Lazy, 10_000_000); + } - ZoneTree2.TestStringTree(WriteAheadLogMode.Immediate, 1_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Immediate, 2_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Immediate, 3_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Immediate, 10_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Lazy, 1_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Lazy, 2_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Lazy, 3_000_000); - ZoneTree2.TestStringTree(WriteAheadLogMode.Lazy, 10_000_000); + public static void LoadAndIterateBenchmark1() + { + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 1_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 2_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 3_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Immediate, 10_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 1_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 2_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 3_000_000); + ZoneTree1.TestInsertIntTree(WriteAheadLogMode.Lazy, 10_000_000); + } + + public static void LoadAndIterateBenchmark2() + { + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 1_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 2_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 3_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Immediate, 10_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 1_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 2_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 3_000_000); + ZoneTree2.TestInsertStringTree(WriteAheadLogMode.Lazy, 10_000_000); + } + + public static void LoadAndIterateBenchmark3() + { + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Immediate, 1_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Immediate, 2_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Immediate, 3_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Immediate, 10_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Lazy, 1_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Lazy, 2_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Lazy, 3_000_000); + ZoneTree3.TestIterateIntTree(WriteAheadLogMode.Lazy, 10_000_000); } } diff --git a/src/Playground/Benchmark/ZoneTree1.cs b/src/Playground/Benchmark/ZoneTree1.cs index 8662e9a..58718fe 100644 --- a/src/Playground/Benchmark/ZoneTree1.cs +++ b/src/Playground/Benchmark/ZoneTree1.cs @@ -9,31 +9,19 @@ namespace Playground.Benchmark; public class ZoneTree1 { - public static void TestIntTree(WriteAheadLogMode mode, int count) + public static void TestInsertIntTree(WriteAheadLogMode mode, int count) { - Console.WriteLine("\r\nTestIntTree\r\n"); + Console.WriteLine("\r\nTestIntTree\r\n"); Console.WriteLine("Record count = " + count); Console.WriteLine("WriteAheadLogMode: = " + mode); var dataPath = "../../data/TestIntTree" + mode + count; if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true); - + var stopWatch = new Stopwatch(); stopWatch.Start(); - using var zoneTree = new ZoneTreeFactory() - .SetComparer(new Int32ComparerAscending()) - .SetMutableSegmentMaxItemCount(1_000_000) - .SetDataDirectory(dataPath) - .SetWriteAheadLogDirectory(dataPath) - .ConfigureWriteAheadLogProvider(x => - { - x.WriteAheadLogMode = mode; - x.EnableIncrementalBackup = false; - }) - .SetKeySerializer(new Int32Serializer()) - .SetValueSerializer(new Int32Serializer()) - .OpenOrCreate(); + using var zoneTree = OpenOrCreateZoneTree(mode, dataPath); using var basicMaintainer = new BasicZoneTreeMaintainer(zoneTree); basicMaintainer.ThresholdForMergeOperationStart = 2_000_000; @@ -47,4 +35,51 @@ public static void TestIntTree(WriteAheadLogMode mode, int count) Console.WriteLine("Completed in: " + stopWatch.ElapsedMilliseconds); basicMaintainer.CompleteRunningTasks().Wait(); } + + public static void TestIterateIntTree(WriteAheadLogMode mode, int count) + { + Console.WriteLine("\r\nTestIterationIntTree\r\n"); + Console.WriteLine("Record count = " + count); + Console.WriteLine("WriteAheadLogMode: = " + mode); + + var dataPath = "../../data/TestIntTree" + mode + count; + var stopWatch = new Stopwatch(); + stopWatch.Start(); + using var zoneTree = OpenOrCreateZoneTree(mode, dataPath); + using var basicMaintainer = new BasicZoneTreeMaintainer(zoneTree); + basicMaintainer.ThresholdForMergeOperationStart = 2_000_000; + + Console.WriteLine("Loaded in: " + stopWatch.ElapsedMilliseconds); + + var off = 0; + using var iterator = zoneTree.CreateIterator(); + while (iterator.Next()) + { + if (iterator.CurrentKey * 2 != iterator.CurrentValue) + throw new Exception("invalid key or value"); + ++off; + } + if (off != count) + throw new Exception($"missing records. {off} != {count}"); + + Console.WriteLine("Completed in: " + stopWatch.ElapsedMilliseconds); + basicMaintainer.CompleteRunningTasks().Wait(); + } + + private static IZoneTree OpenOrCreateZoneTree(WriteAheadLogMode mode, string dataPath) + { + return new ZoneTreeFactory() + .SetComparer(new Int32ComparerAscending()) + .SetMutableSegmentMaxItemCount(1_000_000) + .SetDataDirectory(dataPath) + .SetWriteAheadLogDirectory(dataPath) + .ConfigureWriteAheadLogProvider(x => + { + x.WriteAheadLogMode = mode; + x.EnableIncrementalBackup = false; + }) + .SetKeySerializer(new Int32Serializer()) + .SetValueSerializer(new Int32Serializer()) + .OpenOrCreate(); + } } diff --git a/src/Playground/Benchmark/ZoneTree2.cs b/src/Playground/Benchmark/ZoneTree2.cs index 8790d11..f293b1f 100644 --- a/src/Playground/Benchmark/ZoneTree2.cs +++ b/src/Playground/Benchmark/ZoneTree2.cs @@ -9,7 +9,7 @@ namespace Playground.Benchmark; public class ZoneTree2 { - public static void TestStringTree(WriteAheadLogMode mode, int count) + public static void TestInsertStringTree(WriteAheadLogMode mode, int count) { Console.WriteLine("\r\nTestStringTree\r\n"); Console.WriteLine("Record count = " + count); @@ -21,19 +21,7 @@ public static void TestStringTree(WriteAheadLogMode mode, int count) var stopWatch = new Stopwatch(); stopWatch.Start(); - using var zoneTree = new ZoneTreeFactory() - .SetComparer(new StringOrdinalComparerAscending()) - .SetMutableSegmentMaxItemCount(1_000_000) - .SetDataDirectory(dataPath) - .SetWriteAheadLogDirectory(dataPath) - .ConfigureWriteAheadLogProvider(x => - { - x.WriteAheadLogMode = mode; - x.EnableIncrementalBackup = false; - }) - .SetKeySerializer(new Utf8StringSerializer()) - .SetValueSerializer(new Utf8StringSerializer()) - .OpenOrCreate(); + using var zoneTree = OpenOrCreateZoneTree(mode, dataPath); using var basicMaintainer = new BasicZoneTreeMaintainer(zoneTree); basicMaintainer.ThresholdForMergeOperationStart = 2_000_000; Console.WriteLine("Loaded in: " + stopWatch.ElapsedMilliseconds); @@ -48,4 +36,52 @@ public static void TestStringTree(WriteAheadLogMode mode, int count) basicMaintainer.CompleteRunningTasks().Wait(); Console.WriteLine("\r\n-------------------------\r\n"); } + + public static void TestIterateStringTree(WriteAheadLogMode mode, int count) + { + Console.WriteLine("\r\nTestStringTree\r\n"); + Console.WriteLine("Record count = " + count); + Console.WriteLine("WriteAheadLogMode: = " + mode); + + var dataPath = "../../data/TestStringTree" + mode + count; + + var stopWatch = new Stopwatch(); + stopWatch.Start(); + using var zoneTree = OpenOrCreateZoneTree(mode, dataPath); + using var basicMaintainer = new BasicZoneTreeMaintainer(zoneTree); + basicMaintainer.ThresholdForMergeOperationStart = 2_000_000; + Console.WriteLine("Loaded in: " + stopWatch.ElapsedMilliseconds); + + var off = 0; + using var iterator = zoneTree.CreateIterator(); + while (iterator.Next()) + { + if (iterator.CurrentKey != iterator.CurrentValue) + throw new Exception("invalid key or value"); + ++off; + } + if (off != count) + throw new Exception($"missing records. {off} != {count}"); + + Console.WriteLine("Completed in: " + stopWatch.ElapsedMilliseconds); + basicMaintainer.CompleteRunningTasks().Wait(); + Console.WriteLine("\r\n-------------------------\r\n"); + } + + private static IZoneTree OpenOrCreateZoneTree(WriteAheadLogMode mode, string dataPath) + { + return new ZoneTreeFactory() + .SetComparer(new StringOrdinalComparerAscending()) + .SetMutableSegmentMaxItemCount(1_000_000) + .SetDataDirectory(dataPath) + .SetWriteAheadLogDirectory(dataPath) + .ConfigureWriteAheadLogProvider(x => + { + x.WriteAheadLogMode = mode; + x.EnableIncrementalBackup = false; + }) + .SetKeySerializer(new Utf8StringSerializer()) + .SetValueSerializer(new Utf8StringSerializer()) + .OpenOrCreate(); + } } diff --git a/src/Playground/Benchmark/ZoneTree3.cs b/src/Playground/Benchmark/ZoneTree3.cs new file mode 100644 index 0000000..0d21682 --- /dev/null +++ b/src/Playground/Benchmark/ZoneTree3.cs @@ -0,0 +1,85 @@ +using System.Diagnostics; +using Tenray.ZoneTree; +using Tenray.ZoneTree.Comparers; +using Tenray.ZoneTree.Maintainers; +using Tenray.ZoneTree.Serializers; +using Tenray.ZoneTree.WAL; + +namespace Playground.Benchmark; + +public class ZoneTree3 +{ + public static void TestInsertTransactionIntTree(WriteAheadLogMode mode, int count) + { + Console.WriteLine("\r\nTestIntTree\r\n"); + Console.WriteLine("Record count = " + count); + Console.WriteLine("WriteAheadLogMode: = " + mode); + + var dataPath = "../../data/TestInsertTransactionIntTree" + mode + count; + if (Directory.Exists(dataPath)) + Directory.Delete(dataPath, true); + + var stopWatch = new Stopwatch(); + stopWatch.Start(); + using var zoneTree = OpenOrCreateZoneTree(mode, dataPath); + using var basicMaintainer = new BasicZoneTreeMaintainer(zoneTree); + basicMaintainer.ThresholdForMergeOperationStart = 2_000_000; + + Console.WriteLine("Loaded in: " + stopWatch.ElapsedMilliseconds); + + Parallel.For(0, count, (x) => + { + zoneTree.UpsertAutoCommit(x, x + x); + }); + + Console.WriteLine("Completed in: " + stopWatch.ElapsedMilliseconds); + basicMaintainer.CompleteRunningTasks().Wait(); + } + + public static void TestIterateIntTree(WriteAheadLogMode mode, int count) + { + Console.WriteLine("\r\nTestIterationIntTree\r\n"); + Console.WriteLine("Record count = " + count); + Console.WriteLine("WriteAheadLogMode: = " + mode); + + var dataPath = "../../data/TestInsertTransactionIntTree" + mode + count; + var stopWatch = new Stopwatch(); + stopWatch.Start(); + using var zoneTree = OpenOrCreateZoneTree(mode, dataPath); + using var basicMaintainer = new BasicZoneTreeMaintainer(zoneTree); + basicMaintainer.ThresholdForMergeOperationStart = 2_000_000; + + Console.WriteLine("Loaded in: " + stopWatch.ElapsedMilliseconds); + + var off = 0; + using var iterator = zoneTree.Maintenance.ZoneTree.CreateIterator(); + while (iterator.Next()) + { + if (iterator.CurrentKey * 2 != iterator.CurrentValue) + throw new Exception("invalid key or value"); + ++off; + } + if (off != count) + throw new Exception($"missing records. {off} != {count}"); + + Console.WriteLine("Completed in: " + stopWatch.ElapsedMilliseconds); + basicMaintainer.CompleteRunningTasks().Wait(); + } + + private static ITransactionalZoneTree OpenOrCreateZoneTree(WriteAheadLogMode mode, string dataPath) + { + return new ZoneTreeFactory() + .SetComparer(new Int32ComparerAscending()) + .SetMutableSegmentMaxItemCount(1_000_000) + .SetDataDirectory(dataPath) + .SetWriteAheadLogDirectory(dataPath) + .ConfigureWriteAheadLogProvider(x => + { + x.WriteAheadLogMode = mode; + x.EnableIncrementalBackup = false; + }) + .SetKeySerializer(new Int32Serializer()) + .SetValueSerializer(new Int32Serializer()) + .OpenOrCreateTransactional(); + } +} diff --git a/src/Playground/Program.cs b/src/Playground/Program.cs index d050093..4a75d27 100644 --- a/src/Playground/Program.cs +++ b/src/Playground/Program.cs @@ -1,3 +1,3 @@ using Playground.Benchmark; -BenchmarkGroups.InsertBenchmark(); +BenchmarkGroups.InsertBenchmark1(); \ No newline at end of file diff --git a/src/Playground/Test1.cs b/src/Playground/Test1.cs index 84ea8e9..00057c0 100644 --- a/src/Playground/Test1.cs +++ b/src/Playground/Test1.cs @@ -9,7 +9,7 @@ namespace Playground; public class Test1 { - public void Run() + public static void Run() { var dataPath = "../../data/SeveralParallelTransactions"; var stopWatch = new Stopwatch(); @@ -21,7 +21,7 @@ public void Run() .SetWriteAheadLogDirectory(dataPath) .ConfigureWriteAheadLogProvider(x => { - x.WriteAheadLogMode = WriteAheadLogMode.Lazy; + x.WriteAheadLogMode = WriteAheadLogMode.Immediate; x.EnableIncrementalBackup = true; }) .SetKeySerializer(new Int32Serializer()) diff --git a/src/ZoneTree/Directory.Build.props b/src/ZoneTree/Directory.Build.props index 1dfa0f0..78f0812 100644 --- a/src/ZoneTree/Directory.Build.props +++ b/src/ZoneTree/Directory.Build.props @@ -5,8 +5,8 @@ Ahmed Yasin Koculu ZoneTree ZoneTree - 1.0.7.0 - 1.0.7.0 + 1.0.8.0 + 1.0.8.0 Ahmed Yasin Koculu ZoneTree ZoneTree is a persistent, high-performance key-value database for .NET. It can operate in memory or on a disk. (Optimized for SSDs)