using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Jobs; using ZB.MOM.WW.CBDD.Bson; using ZB.MOM.WW.CBDD.Core; using ZB.MOM.WW.CBDD.Core.Collections; using ZB.MOM.WW.CBDD.Core.Storage; using ZB.MOM.WW.CBDD.Core.Transactions; using Microsoft.Extensions.Logging; using Serilog.Context; using System.IO; namespace ZB.MOM.WW.CBDD.Tests.Benchmark; [InProcess] [MemoryDiagnoser] [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] [HtmlExporter] [JsonExporterAttribute.Full] public class InsertBenchmarks { private const int BatchSize = 1000; private static readonly ILogger Logger = Logging.CreateLogger(); private string _docDbPath = ""; private string _docDbWalPath = ""; private StorageEngine? _storage = null; private BenchmarkTransactionHolder? _transactionHolder = null; private DocumentCollection? _collection = null; private Person[] _batchData = Array.Empty(); private Person? _singlePerson = null; [GlobalSetup] public void Setup() { var temp = AppContext.BaseDirectory; var id = Guid.NewGuid().ToString("N"); _docDbPath = Path.Combine(temp, $"bench_docdb_{id}.db"); _docDbWalPath = Path.ChangeExtension(_docDbPath, ".wal"); _singlePerson = CreatePerson(0); _batchData = new Person[BatchSize]; for (int i = 0; i < BatchSize; i++) { _batchData[i] = CreatePerson(i); } } private Person CreatePerson(int i) { var p = new Person { Id = ObjectId.NewObjectId(), FirstName = $"First_{i}", LastName = $"Last_{i}", Age = 20 + (i % 50), Bio = null, // Removed large payload to focus on structure CreatedAt = DateTime.UtcNow, Balance = 1000.50m * (i + 1), HomeAddress = new Address { Street = $"{i} Main St", City = "Tech City", ZipCode = "12345" } }; // Add 10 work history items to stress structure traversal for (int j = 0; j < 10; j++) { p.EmploymentHistory.Add(new WorkHistory { CompanyName = $"TechCorp_{i}_{j}", Title = "Developer", DurationYears = j, Tags = new List { "C#", "BSON", "Performance", "Database", "Complex" } }); } return p; } [IterationSetup] public void IterationSetup() { _storage = new StorageEngine(_docDbPath, PageFileConfig.Default); _transactionHolder = new BenchmarkTransactionHolder(_storage); _collection = new DocumentCollection(_storage, _transactionHolder, new PersonMapper()); } [IterationCleanup] public void Cleanup() { try { using var _ = LogContext.PushProperty("Benchmark", nameof(InsertBenchmarks)); _transactionHolder?.Dispose(); _transactionHolder = null; _storage?.Dispose(); _storage = null; System.Threading.Thread.Sleep(100); if (File.Exists(_docDbPath)) File.Delete(_docDbPath); if (File.Exists(_docDbWalPath)) File.Delete(_docDbWalPath); } catch (Exception ex) { Logger.LogWarning(ex, "Cleanup warning"); } } // --- Benchmarks --- [Benchmark(Baseline = true, Description = "CBDD Single Insert")] [BenchmarkCategory("Insert_Single")] public void DocumentDb_Insert_Single() { _collection?.Insert(_singlePerson!); _transactionHolder?.CommitAndReset(); } [Benchmark(Description = "CBDD Batch Insert (1000 items, 1 Txn)")] [BenchmarkCategory("Insert_Batch")] public void DocumentDb_Insert_Batch() { _collection?.InsertBulk(_batchData); _transactionHolder?.CommitAndReset(); } }