using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Jobs; using ZB.MOM.WW.CBDD.Bson; using ZB.MOM.WW.CBDD.Core.Collections; using ZB.MOM.WW.CBDD.Core.Storage; namespace ZB.MOM.WW.CBDD.Tests.Benchmark; [SimpleJob] [InProcess] [MemoryDiagnoser] [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] [HtmlExporter] [JsonExporterAttribute.Full] public class CompactionBenchmarks { [Params(2_000)] public int DocumentCount { get; set; } private string _dbPath = string.Empty; private string _walPath = string.Empty; private StorageEngine _storage = null!; private BenchmarkTransactionHolder _transactionHolder = null!; private DocumentCollection _collection = null!; private List _insertedIds = []; [IterationSetup] public void Setup() { var id = Guid.NewGuid().ToString("N"); _dbPath = Path.Combine(AppContext.BaseDirectory, $"bench_compaction_{id}.db"); _walPath = Path.ChangeExtension(_dbPath, ".wal"); _storage = new StorageEngine(_dbPath, PageFileConfig.Small); _transactionHolder = new BenchmarkTransactionHolder(_storage); _collection = new DocumentCollection(_storage, _transactionHolder, new PersonMapper()); _insertedIds.Clear(); for (var i = 0; i < DocumentCount; i++) { var person = CreatePerson(i); var insertedId = _collection.Insert(person); _insertedIds.Add(insertedId); } _transactionHolder.CommitAndReset(); _storage.Checkpoint(); for (var i = _insertedIds.Count - 1; i >= _insertedIds.Count / 3; i--) { _collection.Delete(_insertedIds[i]); } _transactionHolder.CommitAndReset(); _storage.Checkpoint(); } [IterationCleanup] public void Cleanup() { _transactionHolder?.Dispose(); _storage?.Dispose(); if (File.Exists(_dbPath)) File.Delete(_dbPath); if (File.Exists(_walPath)) File.Delete(_walPath); } [Benchmark(Baseline = true)] [BenchmarkCategory("Compaction_Offline")] public long OfflineCompact_ReclaimedBytes() { var stats = _storage.Compact(new CompactionOptions { OnlineMode = false, EnableTailTruncation = true, DefragmentSlottedPages = true, NormalizeFreeList = true }); return stats.ReclaimedFileBytes; } [Benchmark] [BenchmarkCategory("Compaction_Offline")] public long OfflineCompact_TailBytesTruncated() { var stats = _storage.Compact(new CompactionOptions { OnlineMode = false, EnableTailTruncation = true, DefragmentSlottedPages = true, NormalizeFreeList = true }); return stats.TailBytesTruncated; } private static Person CreatePerson(int i) { return new Person { Id = ObjectId.NewObjectId(), FirstName = $"First_{i}", LastName = $"Last_{i}", Age = i % 90, Bio = BuildPayload(i), CreatedAt = DateTime.UnixEpoch.AddSeconds(i), Balance = i * 1.5m, HomeAddress = new Address { Street = $"{i} Long Street", City = "Compaction City", ZipCode = "90000" } }; } private static string BuildPayload(int seed) { var builder = new System.Text.StringBuilder(2500); for (var i = 0; i < 80; i++) { builder.Append("compact-"); builder.Append(seed.ToString("D6")); builder.Append('-'); builder.Append(i.ToString("D3")); builder.Append('|'); } return builder.ToString(); } }